配 列 Java における配列 − その2 − 和田@数理情報科学 このスライドでは このスライドでは、配列操作を以下の例題で順に説明します • • • • • • 要素の合計・平均 2配列の和 配列のコピー 要素の移動 要素の交換 配列の交換 • 要素の並び替え • 時間測定 • ファイルへの入出力 • ベクトルと行列の演算 配 列 繰り返しを用いて合計 1次元 int 型配列 array に入っている値を合計する処理は int[ ] array = { 3, 0, -2, 5, 4, 9, -1, 6, 4 } ; int sum = 0 ; for( int i = 0 ; i < array.length ; i++ ) { sum += array[i] ; } System.out.println( “sum = ” + sum ) ; 要素の平均値を求めるには、上記の結果を要素数で割れば良い ので System.out.println( “average = ” + (double) sum / array.length ); 配 列 スマートに 1次元 int 型配列 array に入っている値を合計する処理は int[ ] array = { 3, 0, -2, 5, 4, 9, -1, 6, 4 } ; int sum = 0 ; for( int element : array ) { sum += element ; } System.out.println( “sum = ” + sum ) ; このような for を拡張 for 文という。配列内の要素を1度ず つ配列番号の順に全て走査する場合のみ利用できる(i+=2) のような飛び飛びでの走査はできない 配 列 2配列の和 要素数の等しい2つの配列の要素番号の等しい要素同士を加え て新たな配列を作るには int[ ] x = { 1, 2, 3, 4, 5 } ; int[ ] y = { 1, 0, -1, 0, 1 } ; int[ ] z = new int[x.length] ; for( int i=0 ; i<x.length ; i++ ) { z[i] = x[i] + y[i] ; } 2つの配列 x と y の長さが異なる場合は、計算できないので、 これらを if( x.length == y.length ) { ・ } のブロックで囲む のも必要か 配 列 配列のコピー 配列 x の中身を丸ごと別の配列 y にコピーしたい時 int[ ] x = { 1, 2, 3, 4 } ; int[ ] y = x ; ではコピーにならない。次のように1要素ずつコピーする: int[ ] x = { 1, 2, 3, 4 } ; int[ ] y = new int[x.length] ; for( int i = 0 ; i<y.length ; i++ ) { y[i] = x[i] ; } でも、もっとスマートな方法もある 配 列 要素の移動 配列内の要素を1つ後へ移動させるには int[ ] x = { 0, 1, 2, 3, 4, 5 } ; for( int i=x.length-1 ; i>0 ; i- - ) { x[i] = x[i-1] ; } 配列内の要素を1つ前へ移動させるには int[ ] x = { 0, 1, 2, 3, 4, 5 }; for( int i=0 ; i<x.length-1 ; i++ ) { x[i] = x[i+1] ; } 配 列 スマートに Java には API (Application Programming Interface) と 言う様々な道具の入ったパッケージ群があるので、それを利用 するとスマートにプログラムを作ることができる 配列のコピーは、 System.arraycopy (Object src, int srcPos, Object dst, int dstPos, int count) によって実行できる: src[srcPos] から始まる配列の内容をdst[dstPos] へ count 個分だけコピーする。src と dst は同じ配列でも良く、部分 的に重なっていても実行できる(要素を移動にも使える) 配 列 arraycopy を使って 配列のコピー: int[ ] x = { 0, 1, 2, 3, 4, 5 } ; int[ ] y = new int[x.length] ; System.arraycopy( x, 0, y, 0, y.length ) ; 要素の移動: int[ ] x = { 0, 1, 2, 3, 4, 5 } ; System.arraycopy( x, 1, x, 0, x.length-1 ) ; 配 列 要素の交換 i 番目の要素と j 番目の要素を交換するには int[ ] x = { 1, 2, 3, 4, 5 } ; int i = 1 ; int j = 3 ; int y = x[i] ; x[i] = x[j] ; x[j] = y ; System.out.println( “x[” + i + “] = ” + x[i] + “ x[” + j + “] = ” + x[j] ) ; 配 列 配列の交換 2つの配列の中身を全て交換する方法は、以前のスライドで行っ た int[ ] x = { 1, 2, 3, 4} ; int[ ] y = { 5, 6, 7, 8} ; int[ ] w = x ; x = y ; y=w; 配 列 要素の並び替え 配列内の要素を昇順(小さい順)や降順(大きい順)に並び替 える(ソートする)には、様々なソート法がある 要素数が少ない配列に対しては、アルゴリズムの簡単な方法を、 要素数が多い配列に対しては、多少複雑でもスピードの速い方 法を選ぶことになる ソート法の比較アプレット: http://www.sorting-algorithms.com/random-initial-order 配 列 挿入法による並び替え 以下の方法が挿入法 (Insertion sort) と呼ばれる方法: int[ ] x = { 6, 5, 2, 7, 4, 1, 3 } ; for( int i = 1 ; i < x.length ; i++ ) { int val = x[i] ; int j = i ; while( j > 0 && x[j - 1] > val ) { x[j] = x[j - 1] ; j- - ; } x[j] = val ; } 6, 5, 2, 7, 4, 1, 3 5, 6, 2, 7, 4, 1, 3 2, 5, 6, 7, 4, 1, 3 2, 5, 6, 7, 4, 1, 3 2, 4, 5, 6, 7, 1, 3 1, 2, 4, 5, 6, 7, 3 1, 2, 3, 4, 5, 6, 7 配 列 選択法による並び替え 以下の方法が選択法 (Selection sort) と呼ばれる方法: int[ ] x = { 6, 5, 2, 7, 4, 1, 3 } ; for( int i = 0 ; i < x.length - 1 ; i++ ) { int min = i ; for( int j = i+1 ; j < x.length ; j++ ) { if( x[j] < x[min] ) { min = j ; } } int y = x[min] ; x[min] = x[i] ; x[i] = y ; } 6, 5, 2, 7, 4, 1, 3 1, 5, 2, 7, 4, 6, 3 1, 2, 5, 7, 4, 6, 3 1, 2, 3, 7, 4, 6, 5 1, 2, 3, 4, 7, 6, 5 1, 2, 3, 4, 5, 6, 7 1, 2, 3, 4, 5, 6, 7 配 列 泡立ち法による並び替え 以下の方法が泡立ち法 (Bubble sort) と呼ばれる方法: int[ ] x = { 6, 5, 2, 7, 4, 1, 3 } ; for( int i = x.length - 1 ; i > 0 ; i- - ) { for( int j = 0 ; j < i ; j++ ) { if( x[j] > x[j+1] ) { int y = x[j] ; x[j] = x[j+1] ; x[j+1] = y ; } } } 6, 5, 2, 7, 4, 1, 3 5, 2, 6, 4, 1, 3, 7 2, 5, 4, 1, 3, 6, 7 2, 4, 1, 3, 5, 6, 7 2, 1, 3, 4, 5, 6, 7 1, 2, 3, 4, 5, 6, 7 1, 2, 3, 4, 5, 6, 7 配 列 実行時間の測定 Java では、2種類の時間測定ができます。 ミリ秒(10-3秒)で測るメソッド: long System.currentTimeMillis() ナノ秒(10-9秒)で測るメソッド: long System.nanoTime() ミリ秒で表される現在の時間を返すが、値の粒度は基本となるオペレー ティングシステムによって異なり、単位がより大きくなる場合がある。 多くのオペレーティングシステムでは、時間を 10 ミリ秒の単位で計 測している。 配 列 Shell 法による並び替え 以下の方法が Shell 法 (Shell s sort) と呼ばれる方法: int[ ] x = { 6, 5, 2, 7, 4, 1, 3 } ; int h = 1 ; for(int i = 1 ; i <= x.length/9 ; i = 3*i + 1) { h = i ; } while( h > 0 ) { for(int i = h ; i < x.length ; i++) { int val = x[i] ; int j = i ; while( j >= h && x[j-h] > val ) { x[j] = x[j - h] ; j -= h ; } x[j] = val ; } h /= 3 ; このデータの場合、h=1 なのだが、 } h=4 で始めている → 6, 5, 2, 7, 4, 1, 3 4, 5, 2, 7, 6, 1, 3 4, 1, 2, 7, 6, 5, 3 4, 1, 2, 7, 6, 5, 3 1, 4, 2, 7, 6, 5, 3 1, 2, 4, 7, 6, 5, 3 1, 2, 4, 7, 6, 5, 3 1, 2, 4, 6, 7, 5, 3 1, 2, 4, 5, 6, 7, 3 1, 2, 3, 4, 5, 6, 7 配 列 マージソートによる並び換え 配 列 以下の方法がマージソート (Merge sort) と呼ばれる方法: int[ ] x = { 6, 5, 2, 7, 4, 1, 3 } ; int[ ] temp = new int[x.length] ; for(int intvl = 1; intvl <= x.length; intvl *= 2) { for(int s1 = 0; s1 < x.length; s1 += intvl * 2) { int e1 = Math.min(s1 + intvl, x.length) ; int s2 = e1 ; int e2 = Math.min(s2 + intvl, x.length) ; int i = s1 ; int j = s2 ; int k = s1 ; while( i < e1 && j < e2 ) { if( x[i] < x[j] ) { temp[k++] = x[i++] ; } else { temp[k++] = x[j++] ; } } while( i < e1 ) { temp[k++] = x[i++]; } while( j < e2 ) { temp[k++] = x[j++]; } System.arraycopy( temp, s1, x, s1, k - s1 ); } } 6, 5, 2, 7, 4, 1, 3 5, 6, 2, 7, 4, 1, 3 5, 6, 2, 7, 4, 1, 3 5, 6, 2, 7, 1, 4, 3 5, 6, 2, 7, 1, 4, 3 2, 5, 6, 7, 1, 4, 3 2, 5, 6, 7, 1, 3, 4 1, 2, 3, 4, 5, 6, 7 クイックソートによる並び換え 以下の方法がクイックソート (Quick sort) と呼ばれる方法: int[ ] x = { 6, 5, 2, 7, 4, 1, 3 } ; int[ ][ ] stack = new int[20][2]; if( l <= r ) { int y = x[l]; x[l] = x[r]; x[r] = y; l++; r--; } } while(l <= r); if(left < r ) { stack[sp][0] = left; stack[sp][1] = r; sp++; } if( l < right ) { stack[sp][0] = l; stack[sp][1] = right; sp++; } int sp = 1; stack[0][0] = 0; stack[0][1] = x.length-1; while( sp > 0 ) { sp--; int left = stack[sp][0]; int right = stack[sp][1]; int l = left; int r = right; int pivot = x[(left+right)/2]; do { while( x[l] < pivot ) { l++; } while( x[r] > pivot ) { r--; } } 6, 5, 2, 7, 4, 1, 3 6, 5, 2, 3, 4, 1, 7 1, 5 2, 3, 4, 6, 7 1, 2, 5, 3, 4, 6, 7 1, 2, 3, 5, 4, 6, 7 1, 2, 3, 4, 5, 6, 7 1, 2, 3, 4, 5, 6, 7 1, 2, 3, 4, 5, 6, 7 配 列 行列の計算 2つの行列 a と b の和を求める int[ ][ ] a = { {1, 2, 3}, {4, 5, 6} } ; int[ ][ ] b = { {0, 1,-1}, {1,-1, 0} } ; int[ ][ ] c = new int[a.length][a[0].length] ; for(int i = 0; i < c.length; i++) { for(int j = 0; j < c[i].length; j++ ) { c[i][j] = a[i][j] + b[i][j] ; } } 配 列 行列の計算 行列 a を転置する int[ ][ ] a = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} } ; for(int i = 0; i < a.length - 1; i++) { for(int j = i + 1; j < a[i].length; j++) { int b = a[i][j] ; a[i][j] = a[j][i] ; a[j][i] = b ; } } 配 列 行列の計算 2つの行列 a と b の積を求める int[ ][ ] a = { {1, 2, 3}, {4, 5, 6} } ; int[ ][ ] b = { {0, 1}, {-1,1}, {-1, 0} } ; int[ ][ ] c = new int[a.length][b[0].length] ; for(int i = 0; i < c.length; i++) { for(int j = 0; j < c[i].length; j++ ) { c[i][j] = 0; for(int k = 0; k < b.length; k++) { c[i][j] += a[i][k] * b[k][j] ; } } } 配 列 ファイルへの読み書き ファイルへの書き込み File file = new File("src/sorting/SortData.txt"); int n = 10000; // 要素の個数 int max = 100000; // 要素の最大値、最小値は 1 // 乱数データのファイル書き込み PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file))); pw.println(n); pw.println(max); for(int i = 0; i < n; i++) { pw.println( (int)(1 + max*Math.random()) ); } Eclipse では、パッケージエクスプローラ内のパッケージを右クリックし pw.close(); 「リフレッシュ」を選択すると作られたファイルが表示される 配 列 ファイルへの読み書き ファイルからの読み込み File file = new File("src/sorting/SortData.txt"); Scanner scan = new Scanner(file); int n = scan.nextInt(); int max = scan.nextInt(); int[] x = new int[n]; for(int i = 0; i<x.length; i++) { x[i] = scan.nextInt(); } scan.close(); 配 列
© Copyright 2024 ExpyDoc