学生向けプログラミング入門

学生向けにプログラミングを解説。Java、C++、Ruby、PHP、データベース

Javaプログラミング入門その11 メソッドが複数あるプログラム

<<前  [TOP]  次>>


メソッドとは、ある特定の一連の処理をまとめたプログラムの構造の1つです。

  • メソッドは必ずクラスの内部に記述しなければいけません。
  • 一つのクラスの中にメソッドは何個でも自由に記述できます。
  • メソッドを記述する順序は処理の順序とは全く関係ありません。
  • メソッドの名前は自由に付けることができます。
  • 習慣では小文字のアルファベットで始まり、長い名前のメソッドの場合には単語の区切りは大文字で表します。


メモ帳を開いて次のプログラムを作ってみましょう。


Sort3.java 直

public class Sort3 { 

	private static int[] test
		= { 10, 75, 24, 32, 98, 72, 88, 43, 60, 35, 54, 62, 2, 12, 82, };

	public static void main( String[] args ) {
		sort( test );

		for( int i=0; i<test.length; i++ ) { 
			System.out.println( (i+1) + ":" + test[i] );
		}
	}
	public static void sort( int[] array ) {
		for ( int i=0; i<array.length-1; i++ ) {
			maxN( array, i );
		}
	}
	public static void maxN( int[] array, int n ) {
		int max = array[n];
		int maxIndex = n;

		for( int i=n+1; i<array.length; i++ ) {
			if( array[i] > max ) {
				max = array[i];
				maxIndex = i;
			}
		}
		array[maxIndex] = array[n];
		array[n] = max;
	}
}



このプログラムでは、メソッドが三つあります。
一つめはsort( )、二つめはmaxN( )、もう一つはmain( )です。
実はmain( )もメソッドなのです。
メソッドの中で、main( )メソッドが必ず一番最初に処理されます。

public static void メソッド名( 引数 ) { }



publicは公開するといった意味があります。
他にはprivate(クラスの内部に限る)など何種類かありますが、今回はあまり深く踏み込みません。
一番最初に宣言する項目です。


次にstaticは静的なという意味があります。
staticを宣言すると、そのメソッドの値をどんどん書き換えて処理させるといったことができなくなります。
このことについてもまた後で説明しますので今はこの部分について解らなくても全然問題ありません。


voidは戻り値が無いメソッドであるということを宣言する型です。void型と言います。
int型やfloat型と同じように型の一つです。
int型を言い変えると整数値で返すといった意味を持っています。
それに対して、void型は返す値が無いということです。
戻り値のあるメソッドは、この先また別のプログラムで説明します。


メソッド名の後の括弧( )の中に引数を入れます。
引数はメソッドの呼び出しの時に入れる引数とイコールの関係を持っています。


ではプログラムを見ながら説明します。


mainメソッドの中に次の記述があると思います。


sort( test );


これがメソッドの呼び出しです。
このようにメソッドを呼び出すには、メソッド名とその括弧( )の中に与えたい引数を記述するだけで良いのです。
sort( test )が処理されると、そのメソッドが処理されます。

public static void sort( int[] array ) {
	for ( int i=0; i<array.length-1; i++ ) {
		maxN( array, i );
	}
}



引数にtestを使っているので、それがarrayに渡されます。


int array = int test;


このメソッドの中では、testがarrayとなって処理されるのです。


このメソッドではすぐfor文でループすることになります。
ループするごとに今度はmaxNメソッドが呼び出されています。
引数はarrayと i です。
引数を記述する前に型の宣言(int[] arrayとint i)が行われているので、呼び出すときは(array, i)というように型を記述する必要はありません。


次に maxNメソッドを説明します。

public static void maxN( int[] array, int n ) {
	int max = array[n];
	int maxIndex = n;

	for( int i=n+1; i<array.length; i++ ) {
		if( array[i] > max ) {
			max = array[i];
			maxIndex = i;
		}
	}
	array[maxIndex] = array[n];
	array[n] = max;
}



sortメソッドから渡された引数は、以下のように代入されます。


int array = int array;
int n = int i;


後の処理はSort.javaで説明した通りで、一番大きな数字を探して前の方と入れ替える作業をします。


それらの作業を受けて、mainメソッドでは出力する作業のみを行っています。


出力結果を確認してみましょう。





メモ帳を開いて次のプログラムを作ってみましょう。


Sort4.java 直

public class Sort4 { 
	private static int[] test
		= { 10, 75, 24, 32, 98, 72, 88, 43, 60, 35, 54, 62, 2, 12, 82, };

	public static void main( String[] args ) {
		sort( test );

		for( int i=0; i<test.length; i++ ) { 
			System.out.println( (i+1) + ":" + test[i] ); 
		}
	}
	public static void sort( int[] array ) {
		int tmp=0;
		for( int i=0; i<array.length-1; i++ ) {
			for( int j=0; j<array.length-i-1; j++ ) {
				if( array[j] < array[j+1] ) {
					tmp = array[j];
					array[j] = array[j+1];
					array[j+1] = tmp;
				}
			}
		}
	}
}



このプログラムは、Sort2.java 直をmainメソッドとsortメソッドに分けて書き直したプログラムです。
作業ごとにメソッドを分けるのは、プログラムが見やすくなるというメリットがあります。


出力結果です。





メモ帳を開いて次のプログラムを作ってみましょう。


Sort5.java 直

public class Sort5 { 

	private static int[] test
		= { 10, 75, 24, 32, 98, 72, 88, 43, 60, 35, 54, 62, 2, 12, 82, };

	private static int[] tmp = null;

	public static void main( String[] args ) {

		sort( test );

		for( int i=0; i<test.length; i++ ) { 
			System.out.println( (i+1) + ":" + test[i] );
		}
	}
	public static void sort( int[] array ) {

		sort( array, 0, array.length-1 );
	}
	public static void sort( int[] array, int min, int max ) {
		if( ( max - min ) < 5 ) {

			sort2( array, min, max );
			return;
		}
		if( tmp == null ) 
			tmp = new int[ array.length ];

			float m = average( array, min, max );
			int largeCount=0;
			int smallCount=0;

			for( int i=min; i<=max; i++ ) { 
				if( array[i] > m ) {
					tmp[ min+largeCount ] = array[i];
					largeCount++;
				}

				else {
					tmp[ max-smallCount ] = array[i];
					smallCount++;
				}
			}
			for( int i=min; i<=max; i++ ) {
				array[i] = tmp[i];
			}
			sort( array, min, min+largeCount-1 );

			sort( array, max-smallCount+1, max );
	}
	private static void sort2( int[] array, int min, int max ) {

		for( int i=min; i<max; i++ ) { 
			for( int j=min; j<max-(i-min); j++ ) {
				if( array[j] < array[j+1] ) {

					int tmp = array[j];
					array[j] = array[j+1];
					array[j+1] = tmp;
				}
			}
		}
	}
	private static float average( int[] array, int min, int max ) {

		float sum = 0.0f;

		for( int i=min; i<=max; i++ ) {
			sum += array[i];
		}
		return sum/( max - min + 1);
	}
}



「private static int[ ] tmp = null;」はこのあとtmp[ ]を使えるようにここで定義しています。
作業領域用データを作成しているだけです。
nullの意味は何もないという意味です。


まずmain( String args )のsort(test)から sort( int array ) { に入ります。
ここで、testがarrayに置き換わります。
なぜ、同じsortメソッドなのにsort( int
array, int min, int max ) メソッドの方に処理が移らないかというと、メソッドの引数の数に理由があります。
引数が一つしかないので、同じsortメソッドなのにsort( int array )の方に処理が移るのです。


sort( int
array ) では、sort( array, 0, array.length-1 )という様にして引数を3つ与えているだけの処理を行っています。
これにより、 sort( int array, int min, int max ) { } にはいります。
ここで、min=0,max=14に置き換わります。(今回のプログラムのみ。与えられるtest
の数によって異なります。)


min=0,max=14なので、最初はif( ( max - min ) < 5 ) の条件に当てはまらず、if( tmp == null ) が呼び出され、temp=array.lengthとなります。


ここで、tmp = new int[ array.length ];について説明します。
new演算子は新しくメモリーを確保するときに用います。
プログラムで配列や変数を扱うときには必ずメモリーを確保しなければなりません。
int[ ] testでは、直接配列に数字を代入しているので、自動的にメモリが確保されています。
しかし、今回のint tmpではnullを代入していましたから、この時点でメモリはまだ確保されていません。
自分でメモリを確保する必要があります。
配列のメモリの確保の仕方は次のように行います。


int
配列名 = new int[確保メモリ数];


intの部分は型名なので、もちろんその時の状況により異なります。


次に、float m = average( array, min, max ); より、float average( int array, int min, int max ) が呼び出され、i=0〜14まで繰り返します。
データの平均が出てreturnします。
ここで、flort m = 平均値となります。


returnについて詳しく説明します。


averageの型がfloatになっているのに注目してください。
今まではvoid型のメソッドしか扱っていませんでした。
void型は戻り値がありませんので、return文は使用しません。
しかし、メソッドの型に戻り値があるような型に指定している場合、return文を使って戻り値を返さなければなりません。


今回の場合は、return sum/( max - min + 1);という記述がこの処理にあたります。
戻り値としてsum/( max - min + 1)という値を返しています。
わかりやすく書くと次のようになります。(実際このように書き換えるとプログラムは動きません。)


float average( int
array, int min, int max ) = sum/( max - min + 1);
それが、sortメソッドに戻り、
float m = average( int[] array, int min, int max )が
float m = sum/( max - min + 1)
という形に書き換えて考えることができます。


float型には数字の最後に f をつけます。
これは決まりなので覚えてください。


次の記述を見てください。

if( array[i] > m ) {
    tmp[ min+largeCount ] = array[i];
    largeCount++;
}
 else {
    tmp[ max-smallCount ] = array[i];
    smallCount++;
}



これにより平均値より大きいものはtmp[0]から順に入っていき、小さいものはtmp[14]からtmp[13],tmp[12]・・と入っていきます。
0〜14まで調べると次に進みます。

for( int i=min; i<=max; i++ ) {
    array[i] = tmp[i];
}



これにより配列tmpの値が配列arrayに代入されます。


sort( array, min, min+largeCount-1 ); によりmin=0,max=largeCount-1(たぶん7)となりまた再びsort( int array, int min, int max ) に入ります。
同時にsort( array, max-smallCount+1, max ); によりmin=max-smallCount+1(たぶん8)、max=14となり sort( int
array, int min, int max ) に入ります。
この時点で、2つのブロックに分けられました。


そして、この2つに分けられたブロックのそれぞれの平均値が出され、それよりも大きいもの、小さいものに分けられます。
この時点で4つのグループに分けられます。


そのとき、if( ( max - min ) < 5 ) の条件に当てはまり、sort2( array, min, max ); から、
sort2( int[] array, int min, int max )メソッドに入りソート(並び替え)されます。


最後にmainに戻り結果がプリントされます。


この並び替えの特徴は、ブロックで分けることによりsort2で処理される並び替えの動作が少なくなることにあります。
ちょっと複雑ですが、並び替えは今までのプログラムより早くできます。


出力結果です。





メモ帳を開いて次のプログラムを作ってみましょう。


Sort6.java 直

public class Sort6 {

        private static int[] test
                = { 10, 75, 24, 32, 98, 72, 88, 43, 60, 35, 54, 62, 2, 12, 82, };

        private static int[] tmp = null;

        public static void main( String[] args ) {

                sort( test );

                for( int i=0; i<test.length; i++ ) {
                        System.out.println( (i+1) + ":" + test[i] );
                }
        }
        public static void sort( int[] array ) {
                sort( array, 0, array.length-1 );
        }
        public static void sort( int[] array, int min, int max ) {
                if( ( max - min ) < 5 ) {
                        sort2( array, min, max );
                        return;
                }
		if( tmp == null )
                        tmp = new int[ array.length ];

			int size = max - min + 1;
			int half = size/2 + size%2;
			sort( array, min, min+half-1 );
			sort( array, min+half, max );

			int counter1 = 0;
			int counter2 = 0;
			for( int i=min; i<=max; i++ ) {
				if( counter1 > (half-1) ) {
					tmp[i] = array[ min+half+counter2 ];
					counter2++;
				}
			else if( counter2 > (max-min-half) ) {
				tmp[i] = array[ min+counter1 ];
				counter1++;
			}
			else if( array[ min+counter1 ] > array[ min+half+counter2 ] ) {
                                        tmp[i] = array[ min+counter1 ];
                                        counter1++;
			}
			else {
				tmp[i] = array[ min+half+counter2 ];
				counter2++;
			}
		}
		for( int i=min; i<=max; i++ ) {
			array[i] = tmp[i];
		}
	}
        private static void sort2( int[] array, int min, int max ) {
	      for( int i=min; i<max; i++ ) {
			for( int j=min; j<max-(i-min); j++ ) {
		                if( array[j] < array[j+1] ) {
		                        int tmp = array[j];
					array[j] = array[j+1];
	                                array[j+1] = tmp;
				}
			}
            }
	}
}



private static int[ ] tmp = null; で作業領域用データtmp[ ]を作ります。


まずmain( String[ ] args )のsort(test)から sort( int[ ] array ) { にはいります。
ここで、testがarray[ ]に置き換わります。


sort( int[ ] array ) でsort( array, 0, array.length-1 )により sort( int[ ] array, int min, int max ) に入ります。
ここで、min=0,max=14に置き換わります。(今回のプログラムだけ)


最初はtmp = nullなので if ( tmp == null ) が呼び出されます。

最初はint size=15,half=8となり、sort( array, min, min+half-1 )でmin=0,max=7,
sort( array, min+half, max )でmin=8,max=14となり、それぞれまたsort( int array, int min, int max )のループに入ります。

sort( array, min, min+half-1 )では、min=0,max=7なので、またmin=0,max=3とmin=4,max=7の2つに分けられます。
sort( array, min+half, max )では、min=8,max=14なので、min=8,max=11とmin=12,max=14の2つに分けられます。
それぞれ再びsort( int array, int min, int max ) のループに入ります。
ここで、配列は次の4つの組に分けられています。


1組 10, 75, 24, 32


2組 98, 72, 88, 43


3組 60, 35, 54, 62


4組 2, 12, 82


return文 でループは終わります。


ここのreturn文は戻り値を返すためではなく、この処理を終わらせる意味を持っています。
このreturn文がないと、このメソッドの繰り返しループが永遠に繰り返されてしまい、最終的にはメモリを食い尽くしてしまう恐れがあります。
このreturn文があることで、sort( array, min, min+half-1 )とsort( array, min+half, max )のそれぞれの場所まで戻ります。
同じメソッドを繰り返して使うときは、最後の処理の時にreturn文をつけなければうまく動かなくなりますので気をつけてください。


ソートされた4組はループに入る前まで戻され(4つの組に分けられる前、もっと解りやすく言うと、まだ2つの組の時でsortメソッドに入るとき)、min=0,max=7, とmin=8,max=14の2組がそれぞれfor( int i=min; i<=max; i++ )のループにはいります。


2組は次のような順序になっている。


1組 75,32,24,10, 98,88,72,43,


2組 62,60,54,35, 82,12,2


これまでの流れを解りやすくしてみましたので参考にしてください。


処理A     size=15、min=0、max=14
array[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14]
数字10752432987288436035546221282


これは、一番最初の状態です。
次にこれを半分にしてまたsortメソッドに入ると次のようになります。


処理B   size=8,min=0,max=7   size=7,min=8,max=14
array[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14]
数字10752432987288436035546221282


この二つがそれぞれまたsortメソッドに入って半分にされると次のように4分割されます。


処理Csize=4,min=0,max=3size=4,min=4,max=7size=4,min=8,max=11size=3,min=12,max=14
array[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14]
数字10752432987288436035546221282


これがまたそれぞれsortメソッドに入るのですが、ここで今まで当てはまらなかった次の条件の処理に移ります。

if( ( max - min ) < 5 ) {
    sort2( array, min, max );
    return;
}



これにより、4つのブロックのそれぞれが並び替えされ次のようになります。


処理Csize=4,min=0,max=3size=4,min=4,max=7size=4,min=8,max=11size=3,min=12,max=14
array[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14]
数字75322410988872436260543582122


この並び替えが終わったらreturn文によりこのメソッドループが終わります。
このメソッドのループを再帰的ループといいます。
このreturn文によりどこまで処理が戻るかというと、処理Bのところまで戻ります。
戻ったら次のようになっています。


処理B  size=8,min=0,max=7   size=7,min=8,max=14
array[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14]
数字75322410988872436260543282122


この2つのブロックがそれぞれ次のfor文の処理に移ります。

int counter1 = 0;
int counter2 = 0;
for( int i=min; i<=max; i++ ) {
      ・
      ・
      ・


このfor文の処理を説明するのに、size=8,min=0,max=7の配列{75,32,24,10,98,88,72,43}の方の処理を見ながら説明します。


まず、couter1とは[0]〜[3]の配列{75,32,24,10}を示します。
couter2は[4]〜[7]の配列{98,88,72,43}を示します。


このif文の意味は、簡単に言うと両方のブロックの先頭同士をまず比べ(今回は75と98)、大きいほうをtmp[0]に代入します。
代入したほうのブロックのcounterをひとつインクリメントします。
次は75と88を比べてといった処理をfor文で繰り返しているだけです。


この処理は、実際に数字を当てはめて見ていけば解りやすいです。
このループが全部終わると今度は処理Aに再び戻ります。
戻ったときには次のようになっています。


処理A            size=15、min=0、max=14
array[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14]
数字98887572433224108262605435122


この2つのブロックがまた次のループに入ります。


int counter1 = 0;
int counter2 = 0;
for( int i=min; i<=max; i++ ) {
      ・
      ・
      ・


この処理が終わると、すべてが並び替えられていてmainメソッドに戻り結果が出力されます。


出力結果です。





<<前  [TOP]  次>>