Upload
gamma
View
30
Download
2
Embed Size (px)
DESCRIPTION
オブジェクト・プログラミング. 第 7 回 アルゴリズム. 前回多かった質問. 要素が少ないとき、 0ms と出てしまう。 この方法では ms 以下の時間は計れないので、仕方がないです。コンピュータは ms より小さい単位で動いています。 毎回かかる時間が微妙に違う Windows がマルチタスクなためです。 よって、この手の考察を行う場合、何回かの平均を取るべきです。(そんなプログラムは簡単に書けるでしょう!?). 前回の経験より. リニアサーチを使うのは次の場合に限られる。 要素が少ない時 ( 数十個程度 ) ソートされていないデータに対する時 - PowerPoint PPT Presentation
Citation preview
オブジェクト・プログラミング
第 7 回
アルゴリズム
前回多かった質問 要素が少ないとき、 0ms と出てしまう。
この方法では ms 以下の時間は計れないので、仕方がないです。コンピュータは msより小さい単位で動いています。
毎回かかる時間が微妙に違う Windows がマルチタスクなためです。 よって、この手の考察を行う場合、何回か
の平均を取るべきです。(そんなプログラムは簡単に書けるでしょう!?)
前回の経験より リニアサーチを使うのは次の場合に限ら
れる。 要素が少ない時 ( 数十個程度 ) ソートされていないデータに対する時
だけどバイナリサーチはソート(順番に並んでいる)されていなければ、使えない!
今日は、ソートを学びます。
今週の目標 ソートのアルゴリズムについて説明す
ることができる。(教科書第 3 章) Java でソートをするプログラムが書ける
ようになる。 Java のテクニックを学ぶ
ランダムに商品情報を作る。 ファイルの入出力を行う。
今日は簡単なソートをやります ソートは重要で時間のかかる処理なので、これま
でにも多くのコンピュータ科学者が研究に取り組み、いくつかの高度な方法も発明されています。
その中で比較的簡単な 3 つの方法を紹介します。 バブルソート 選択ソート 挿入ソート
これらのテクニックは素朴で、遅いアルゴリズムですが、勉強する価値はあります。単に分かりやすいだけでなく、データの並び方や数によって、これらの方法のほうが速い場合もあるからです。
バブルソート アルゴリズム
(1)2 つの商品番号を比較する (2) 左側の方の番号が大きければ商品情報を入れ
替える。 (3) 右へ一つ移動する。 ソートの終ってない部分 ( 毎回小さくなる ) に対
して上のステップを繰り返す
※ 配列の一番左の箱の中の番号が最小になるように並べ替える場合です。
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
103 22 51 3 64 18
※ 実際にはオブジェクトが入りますが、今日は見やすいように番号だけが入っているように見せます。
バブルソート
比較する
22 103
入れ替える
一つ移動する
比較する
51 103
入れ替える
一つ移動する
比較する
3 103
入れ替える
一つ移動する
比較する
64 103
入れ替える
一つ移動する
比較する
18 103
入れ替える
一つ移動するもう一度始めから
比較する
22 51
そのまま
一つ移動する
比較する
3 51
入れ替える
一つ移動する
比較する
51 64
そのまま
一つ移動する
比較する
18 64
入れ替える
一つ移動する
ソート済みソート済み
とやっていくと、最後にソートされます。
コンピュータでの「入れ替え」(Swap) 前ページの例では、「入れ替え」を一
瞬で行っていましたが、実はコンピュータはそのような操作はできません。
[0] [1]
51 33 51
入れ替える
コンピュータでの「入れ替え」(Swap) やり方 temporary の箱を利用します。
[0] [1] tmp
51 3 3
コピー
51
コピー
3
コピー
入れ替え完了!これを何回もやるのは結構時間かかります。
バブルソートの効率 問題:バブルソートの効率を考えなさ
い。 ① 比較の回数 ② 入れ替えの回数を考えなさい。
バブルソートの効率(答え) ① 比較の回数
2 要素のとき→ 1 回 3 要素のとき→ 1+2 回 4 要素のとき→ 1+2+3 回 N 要素のとき→ (N-1)+(N-2)+(N-3)…+1 回=N*(N-1)/2=N^2/2 回
② 入れ替えの回数 確率的に、比較したうちの半分を入れ替える。 よって、約N^2/2 /2 = N^2/4 回
バブルソートの実装
// バブルソートをするメソッド (ItemInfoFolder クラス )public void bubbleSort(){ for(int i=size-1;i>1;i--){// 要素数回始めから作業を繰り返す for(int j=0;j<i;j++){// ソート済みの所まで作業する if(itemInfoArray[j].no > itemInfoArray[j+1].no){ swap(j,j+1);// もし右側のほうが大きかったら入れ替える } } }}
※swap メソッドは次のページ
入れ替え (swap) の実装
// 要素を入れ替えるメソッドpublic void swap(int target1,int target2){
ItemInfo temp;//temporary の箱を用意する
temp = itemInfoArray[target1];
itemInfoArray[target1] = itemInfoArray[target2];
itemInfoArray[target2] = temp;}
選択ソート アルゴリズム
(1) 全商品番号から、一番小さい番号を探す。
(2) 見つかったものと、一番左の商品情報を入れ替える。
ソートの終ってない部分 ( 毎回小さくなる ) に対して上のステップを繰り返す。
選択ソート
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
103 22 51 3 64 18
最小値の入っている箱の番号
0
比較する
1
最小値を更新する
比較する比較する比較する比較する
3
最小値を更新する
入れ替える
最小値が見つかった!
3 103
ソート済み
ここからまた同じことをはじめる
1
最小値を更新する
比較する比較する比較する比較する
5
最小値を更新する
最小値がみつかった
入れ替える
18 22
ソート済み
このようにして、ソートが終わるまで続けます。
選択ソートの効率 ① 比較の回数
2 要素のとき→ 1 回 3 要素のとき→ 1+2 回 4要素のとき→ 1+2+3 回→バブルソートと同じ。約N^2/2 回
② 入れ替えの回数 2 要素のとき→ 1 回 3 要素のとき→ 2 回 4要素のとき→ 3 回→位置の入れ替えは N回ですむバブルソートより少しだけ速い。
選択ソートの実装 // 選択ソートをするメソッド (ItemInfoFolder クラス ) public void selectionSort(){ for(int i=0;i<size-1;i++){// 要素数回始めから作業を繰り返す int minimum = i;// 最小値の配列番号を保存しておく for(int j=i+1;j<size;j++){// ソート済み以降を作業する if(itemInfoArray[j].no < itemInfoArray[minimum].no){ minimum = j;// 最小値より小さかったら、新しい最小値に } } swap(i,minimum);// 一番左の要素 ( ソート済み除く ) と // 最小と入れ替える } }
挿入ソート アルゴリズム
(1) 途中までソートが終わっているとします。(そのほうが理解しやすいので)
(2) ソートが終わっていない中で、一番左にある商品情報をソート済みの商品情報の中で、あるべき位置に挿入します。
ソートの終ってない部分 ( 毎回小さくなる ) に対して上のステップを繰り返します。
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
3 18 22 51 64 18 103
tmp
挿入ソートソート済み
次に挿入すべき商品情報入れるところを探すここだ!
22
コピー
3 18 51 64 22 18 103
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
3 18 51 64 22 18 103
コピーする
22 51 64
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
3 18 22 51 64 18 103
移動
これを繰り返します。
次に挿入するターゲット
ソート済み部分が増えた!
挿入ソートの効率 ① 比較回数
2 要素のとき→ 1 回 3 要素のとき→ 1+2 回 4要素のとき→ 1+2+3 回 挿入ソートの場合、上記は最大比較回数で、確率的に、だい
たいそれより早く見つかるので、N^2/2 /2=N^2/4となる。N2乗のオーダーは変わらないが、バブル、選択ソートより、約 2倍速い。
② 入れ替え回数 入れ替えも比較の回数とほぼ同じであるが、挿入ソートでは、
入れ替えではなく、隣にコピーするだけであるため、多少効率は良い。
場合によって効率が変わる! 挿入ソートは、ほとんどソートされて
いるときには、とても効率的。
逆に、逆順にソートされている場合、最大の比較回数と移動回数が実行されてしまい、バブルソートと同じ遅さになってしまう。
挿入ソートのアルゴリズム// 挿入ソートをするメソッド (ItemInfoFolder クラス )public void insertionSort(){ int target;// 挿入する対象 for(target = 1;target<size;target++){ ItemInfo temp = itemInfoArray[target];// 対象をコピーする int i=target; while(i>0 && itemInfoArray[i-1].no > temp.no){// 挿入場所に 出会うまでシフトしつづける itemInfoArray[i] = itemInfoArray[i-1];// 右へシフト i--; } itemInfoArray[i] = temp;// 対象を挿入する }}
挿入ソートをあと少しだけ効率化する。
// 前ページのプログラムと同じです。public void insertionSort(){ int target; for(target = 1;target<size;target++){ ItemInfo temp = itemInfoArray[target]; int i=target; while(i>0 && itemInfoArray[i-1].no > temp.no){ itemInfoArray[i] = itemInfoArray[i-1]; i--; } itemInfoArray[i] = temp; }}
この行に注目!!
非効率な条件文 while(i>0 && itemInfoArray[i-1].no > temp.no)
日本語に直すと、 ①i が 0 以上で、 かつ、 ② 配列の中の商品番号が、対象商品番号より大きい間となる。
ようは、挿入すべき場所を探しているのだが、この中で①の条件は、ほとんど成り立たない(後述)にもかかわらず、 N^2/4 回行われてしまう。これは Nが増えたときにボトルネックにになってしまう。何とかして、条件は一つにしたいな。
i<0 の条件をなくすと何故まずい?
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
18 35 2 46 8
ソート済み
挿入対象
こんな時、 i は 0 以下になってしまい、-1 の配列をアクセスしてしまい、ArrayIndexOutOfBoundsException が出てしまいます。何故かは考えてみよう!
[-1]
条件をなくしてもエラーをなくす方法
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
番兵くん登場!
18 35 2 46 8-1
番兵くん
こいつに絶対ありえない小さいの商品番号(この場合、商品番号は必ず正だとすると -1 とか -10000000 とかを入れておく)入れておけば、 i>0 の条件を抜いても、絶対に配列からはみ出さない。
だけど -1 なんていう配列は作れない。 0 番目を番兵用に空けます。
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
18 35 2 46 8-1
番兵用※ 0番目は番兵用に空けるため、挿入のときなどのプログラムにも工夫が必要になります。
番兵を使うときの注意 番兵を使うと、使える配列は一つ少な
くなるので注意! いっぱいにはしないとか、一つ増やした配
列を用意するなどの対応を取るのが一般的。
今回は配列の一番始めに番兵を立てますが、アルゴリズムによっては、一番最後に番兵を立てる場合もあります。
番兵を利用した場合の while文 番兵以前
while(i>0 && itemInfoArray[i-1].no > temp.no)
番兵以後 while(itemInfoArray[i-1].no > temp.no)
さらに、、
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
18 35 2 46 818 35 2 46 8-1
対象temp
2
さっきは temp 用の箱を用意しましたが、、、
番兵を利用して、もっとスマートなアルゴリズムに
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
18 35 2 46 818 35 2 46 8-1
対象
2
自分自身を番兵として入れるとTemp の代わりになり、スマートです。
なぜ、自分自身を入れても、番兵としての役割を果たせるのか考えてみよう!
今週の課題 今週はソートの時間を計ってもらいま
す。 ItemInfoFolder に
バブルソートを行う bubbleSort() メソッド 選択ソートを行う selectionSort() メソッド 挿入ソートを行う insertionSort() メソッド
を加え、実装しなさい。
今週の課題(続き) 実装した3つのソートの性能を時間を
計って、比べなさい。 要素数は、最低 4種類で行いなさい。
どれぐらいがよいかは自分で判断すること。
発展問題 ( 必修ではない ) 番兵付き挿入ソートを行う insSortWithGua
rd() メソッドを作ってそれも考察しなさい。
課題のために 今回の課題では、ソートされていない、
商品情報をたくさん作る必要があります。
ランダムに商品情報を作る方法を紹介します。
ランダムに数値を発生させる Math.random() メソッドを使います。
このメソッドの返り値は double 型で、0 ~ 1 の間のランダムな数を返します。
1 ~N までのランダムな数を発生させる。 double randomNo = Math.random(); int itemNo = (int)(randomNo*N)
実際の数字を入れます。double 型を int 型に変換します。
何回も同じ条件で実行したい 毎回ランダムに数字を発生させて実験する
と、毎回違う条件になってしまいます。→ソートは条件が変わると性能も変わる
毎回同じ条件で商品情報を生成できるように、ランダムに数字を生成したら、ファイルに書き出しておくことにします。
ファイルに書き出しておこう!
ランダムに数字を発生し、ファイルに書き出すプログラム
ソートを実行するプログラム(VendingMachineMain)
書き出し読み込み
1028358349338…
番号を書きとめておくファイルrandomNo.txt( 名前は任意 )
ファイルに読み書きする方法
プログラム
書き出しBufferedWriter クラスOutputStream クラスFileOutputStream クラス
読み込みBufferedReader クラスInputStream クラスFileInputStream クラス
Java では、簡単にできるように以下のクラスが用意されています。
ファイル
Java でファイルを扱う これらのクラスを扱う際には、必ず、
import java.io.*;と宣言します。(クラス宣言の前にすること)package vendingmachine;
import java.io.*;
public class RandomItemInfoMaker{ …}
注: Package 文はなくてもよい。
ファイルの書き出し// ファイルの書き出し部分だけ抜粋 try{ // ファイル出力のための BufferedWriter クラスを生成します。 FileOutputStream fos = new FileOutputStream("randomNo.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos); BufferedWriter bw = new BufferedWriter(osw);
bw.write(“Test”);//write() メソッドで書き込みます。 bw.newLine();//newLine() メソッドで改行します。 bw.close();//close() メソッドでファイルを閉じます。
}catch(Exception ex){ ex.printStackTrace(); }
書き出すファイル名
全体を try{ }catch で囲む必要があります。これについては、後にやります。
ファイルの読み込み// ファイルの読み込み部分だけ抜粋 try{ // ファイル出力のための BufferedReader クラスを生成します。 FileInputStream fis = new FileInputStream("randomNo.txt"); InputStreamReader isr = new InputStreamReader(fis); BufferedReader br = new BufferedReader(isr);
String line = br.readLine()//readLine() メソッドで一行読み込み、 読み込んだ文字列を返り値として返します。 bw.close();//close() メソッドでファイルを閉じます。
}catch(Exception ex){ ex.printStackTrace(); }
読み込むファイル名
全体を try{ }catch で囲む必要があります。これについては、後にやります。
その他は質問どうぞ 以下の2つのプログラムを配ります。
Random に数字を生成して、ファイルへの書き出しができるプログラムの RandomItemInfoMaker クラス
そのファイルを読み込んで、ランダムな商品番号の ItemInfo クラス生成できる VendingMachineMain クラス
なるべくコメントを書いておきますが、分からない点は TA に質問してください。
提出方法 [email protected] 宛て。 今回もソースのほかに、
実行結果、考察を書いて送ってください。(ただし、ソースは ItemInfoFolder だけでよい。 ) ( 感想を任意でお願いします。 )
Subject はログイン名を必ず書いてください。 ex) t96844ym 余計な [] などをつけないでください。
水曜まで。