• 検索結果がありません。

第8回 検索とその効率

N/A
N/A
Protected

Academic year: 2021

シェア "第8回 検索とその効率"

Copied!
43
0
0

読み込み中.... (全文を見る)

全文

(1)

第8回 検索とその効率

~効率の良いプログラムとは?~

(2)

学習目標

効率が考慮されたプログラムが書ける

効率の悪いプログラムを使うとどうなるか 説明できる

効率を指標 (BigO 記法 ) を使って説明でき

バイナリサーチを Java で実装できる

アルゴリズムをオブジェクトにしたプ ログラムが書ける

(3)

8.1 プログラムと効率

8.1.1

プログラムの効率が悪いとどうな

る?

8.1.2

性能を測るプログラム

8.1.3

効率の計測結果についての考察

8.1.4

追加の効率をあげる

(4)

8.1.1 プログラムの

効率が悪いとどうなる?

品質の高いプログラムって?

正しさ

使いやすさ

再利用性

可読性(読みやすさ)

効率(速さ)

(5)

効率が悪いとどうなるか?

1万人の社員がいる会社があります。

ログインするために社員番号でパス ワードを検索します。

1人の検索に

0.

1秒かかると、全員が ログインし終わるまでに何分かかりま すか?

こたえ :

1分で600人だから

10000/600=16.66 分   →大変だ!

(6)

今回考えること

今回はたくさんの商品種類を取り扱います

1万個の商品種類

10万個の商品種類

現実の自動販売機ではありえませんが、コ ンピュータの自動販売機ならできます

例えば、 WEB でソフトやゲームを販売する場 合。

(7)

8.1.2 性能を測るプログラム

今回、次回は配列実装版だけ扱います

(例題

8-1

ItemTypeArrayList→ ItemTypeList

(8)

時間を計る方法

前回のプログラムは意味が明確でない

StopWatch クラスの作成

(9)

StopWatch クラス

public class StopWatch {

long startTime;//開始した時間を保存する変数 long stopTime;//停止した時間を保存する変数 /**

* ストップウオッチをスタートさせる */ public void start(){

startTime = System.currentTimeMillis();//開始した時間を保存しておく }

/**

* ストップウオッチを停止させる */ public void stop(){

stopTime = System.currentTimeMillis();//停止した時間を保存しておく }

/**

* 開始から終了までにかかった時間を取得する */ public long getTime(){

long time = stopTime - startTime;//開始時間 - 停止時間をかかった時間とする return time;

(10)

追加の時間を測る

public static void main(String[] args) {

StopWatch sw = new StopWatch();// ストップウオッチをインスタンス化

ItemTypeList itemTypeList = new ItemTypeList();// 配列版をインスタンス化 int addItemTypeId = 10000;// 商品種類を追加 / 検索する数

// 商品種類を追加する

sw.start();// ストップウオッチをスタート // 指定された回数追加する

for(int i=0; i<addItemTypeId; i++){

itemTypeList.add(new ItemType(i, "商品種類 "+i,120));

}

sw.stop();// ストップウオッチを止める

long time = sw.getTime();// かかった時間

System.out.println(" 追加にかかった時間は "+time+" ミリ秒です ");

}

ストップウオッチを スタート

1 万回 ストップウオッチを停止追加

(11)

8.1.3 効率の

計測結果についての考察

1

万個追加はそれなりの速さです

(Pentium700MHz

で約

0.7

)

ですが、

2

万個では

2.8

秒になり、

10

万個は信じられないくらい遅いです

何故か考えてみましょう!

(12)

if 文の回数を調べる

add

メソッドの

if

文は何回実行されている でしょうか?

1

万回の時と

10

万回の時でどうでしょう?

/**

* 商品種類を追加する

*/ public void add(ItemType addItemType){

// 商品種類が入っていない箱を探す

for(int i=0; i<ARRAY_SIZE; i++){

if(itemTypeArray[i] == null){// 入っていない itemTypeArray[i] = addItemType;// 書き込む break;

} } }

(13)

計算方法

1

個追加の時→

1

2

個追加の時→

1

2

回=

3

3

個追加の時→

1

2

3

回=

6

100

個追加の時→

1+2+...+100

=(1+100)×50 = 5050

N

個挿入の時→

(1+N)×N/2

=

N^2/2

(14)

10 万要素追加に かかる時間予測

10000 個のとき

10000×10000 / 2

= 50,000,000 回(5千万回 )

      

0.7

100000 個のとき

100000×100000 / 2

= 5,000,000,000 (50 億回 )                   おそらく 70

(15)

8.1.4 追加の効率を上げる

追加する番地を覚えておけばよい

変数に size を加えます

//ItemTypeArrayList クラス

public class ItemTypeArrayList implements …{

private ItemType[] itemTypeArray = … private int size = 0;

}

例題8-2

(ItemTypeList.java)

(16)

効率のよい追加のプログラム

public class ItemTypeArrayList implements ItemTypeList{

private ItemType[] itemTypeArray;// 商品種類を保存する配列 private int size = 0;// 現在の要素数

/**

* 商品種類を追加する

*/ public void add(ItemType addItemType){

itemTypeArray[size] = addItemType;// 空の箱から順に書き込む size++;// 要素数を 1 つ増やす

} }

if 文がなくなった!

一つ追加したら、要素数を一つ増やします

(17)

削除のプログラムも変更

  // 商品種類を削除するメソッド

public void delete(int deleteId){

int i=0;// ループの回数を保存する for(i=0;i<size;i++){

if(itemTypeArray[i].getId() == deleteId){// 見つかった

itemTypeArray[i] = null;//見つかったら、削除する(実は不要)

break;

} }

// 残りの要素をシフトする for(;i<size-1;i++){

itemTypeArray[i] = itemTypeArray[i+1];

}

size--;

}

一つ削除したら、要素数を一つ減らします

(18)

検索、削除の

プログラムも少し効率化

// 商品種類を検索するメソッド

public boolean search(int num){

for(int i=0;i<ARRAY_SIZE;i++){

if(itemTypeArray[i] != null){

if(itemTypeArray[i].id == num){

return true;

} } }

return false;

}

// 商品種類リスト種類を検索するメソッド public boolean search(int num){

for(int i=0;i<size;i++){

if(itemTypeArray[i].id == num){

return true;;

} }

return false;

}

入っている分だけ検索 配列全部を検索

null チェック

size 導入前 size 導入後 必要なし

(19)

速くなったかな?

実験結果

1 万個 (Pentium700MHz) 0.08 秒!

2 万個でも 0.14 秒です

これで運用でも耐えられそうです

(20)

8.2 検索アルゴリズム

8.2.1

検索の効率を考える

8.2.2

リニアサーチ

8.2.3

バイナリサーチ

(21)

8.2.1 検索の効率を考える

検索の実験結果

1 万個- 2 5

2 万個- 20

これでは実用に耐えません

(22)

if 文の実行回数を調べる

例によって

if

文の実行回数を調べます

// 商品種類を検索するメソッド

public boolean search(int searchId){

for(int i=0;i<size;i++){

if(itemTypeArray[i].getId() == searchId){

return true;

} } }

return false;

}

(23)

場合によって異なる

0

を検索した場合→1回の

if

文で見つかる

9999

を検索した場合→1万回の

if

文で見 つかる

平均 5000 回の if 文で見つかる

よって、 if 文の回数は 5000×10000=50,000,000 ( 5千万回 )

よって、 n 個の検索で必要な if 文の数は n/2 × n = n^2/2

(24)

10 万回検索をしたら

10万要素を10万回検索した場合は、

100000×100000 /2 = 5,000,000,000 (50

億回

)

の比較が必要

理論上は

50

秒で検索が終わります

ですが、実際にやってみると、7分ぐらい かかります。これはインスタンスにアクセ スのオーバーヘッドが大きくなるためです

(25)

8.2.2 リニアサーチ

前回までの方法を「リニアサーチ」と いいます。

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

4 5 6 7 8 9 10

3 2

1

9を探す場合

[10]

11

あった!

(26)

8.2.3 バイナリサーチ

バイナリサーチ

配列の中身がソート済み(順番に並んでい る)の場合に有効

今回は for 文で順番に追加されているのでソー ト済みになっています

(27)

バイナリサーチの考え方 (1)

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

4 5 6 7 8 9 10

3 2

1

9を探す場合

[10]

11

まず、真ん中を探します。

ちがった!

② 違った場合も、探す範囲は半分に絞られます。

(数が少なかったら右半分、逆なら左半分にあります。)

9は6より大きいから、

(28)

バイナリサーチの考え方 (2)

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

4 5 6 7 8 9 10

3 2

1

9を探す場合

[10]

11

次に、その範囲の中のまた真ん中を探します。

ちがった!

それを見つかるまで繰り返します。

9は8より大きいから、

この範囲に絞られる

(29)

① バイナリサーチの実装

// バイナリサーチをするメソッド

public boolean search(int searchId){

int lower = 0;// 探す配列の範囲の最小値

int upper = size-1;// 探す配列の範囲の最大値 int center;// 次に調べるべき配列の番地

while(true){

center = (lower + upper)/2;// 次に調べるのを範囲の真中に設定 if(itemTypeArray[center].id == searchKey){

return true;// 見つかった }else if(lower > upper){

return false;// 見つからず、かつ、もう調べる範囲がなくなった }else{

// 見つからないので、次に調べる範囲を狭める

if(itemTypeArray[center].id < searchKey){

lower = center +1;// 範囲を右半分にする }else{

upper = center -1;// 範囲を左半分にする }

} }

例題8-3

(ItemTypeList.java)

(30)

② バイナリサーチの効率

例えば、

100

個の要素の中から検索す ることを考えてみましょう。

リニアサーチの場合

比較の回数は   -最小の場合で1回

      -最大の場合で100回       -平均50回

バイナリサーチの場合

比較の回数は   -最小の場合で1       -最大の場 合で7回      -平均7回 以下

(31)

要素数 比較最大回数

10 10

100 100

1000 1000

10000 10000

100000 100000

1000000 1000000

10000000 10000000

リニアサーチ バイナリサーチ 2

7 10 14 17 20 24

バイナリサーチの効率(2)

(32)

バイナリサーチの効率(3)

バイナリサーチ

の比較回数 検索できる範囲

1 2

2 4

3 8

4 16

5 32

6 64

7 128

0 1

2^ 比較回数

ようするに

「2の巾乗」

が検索できる範囲 になる。

(33)

2の巾乗を逆計算する

問題:

100

をバイナリサーチすると、最 大何回の比較が必要か。計算で求めよ

答え log2(100) = 6.644

切り上げて 7

(34)

8.3 効率を比較する

8.3.1 BigO

記法

(35)

検索の効率を比較する

N

つの要素の中から検索するときの効 率は、以下のように計算されます。

リニアサーチの場合

比較の回数は   -最小の場合で 1

      -最大の場合で N       -平均 N/2

バイナリサーチの場合

比較の回数は   -最小の場合で1回       -最大の場合で log2(N)

      -平均 log2(N)

N に比例

Log2(N) に比例

(36)

効率を比べる一般的な記法

BigO

記法

BigO 記法は、その名の通り、大文字の O を使いますが、 order( 次数 ) の意味です。

O(N)

bigO 記法

O(LogN) O(N^2)

N に比例

Log2(N) に比例 N の2乗に比例

(37)

BigO のグラフ化

0 5 10 15 20 25 30 35 40

1 2 3 4 5 6 7 8 9 10 11 12 13

O(N) O(N )^2 O(logN) O(1)

(38)

8.4 アルゴリズムを

比較するプログラムの設計

リニアサーチとバイナリサーチを比較 するプログラムの設計をしましょう

リニアサーチとバイナリサーチを使い分け ることができる設計にしたい

どんなプログラムを書いたらよいです か?

(39)

案Ⅰ:メソッドを分ける

メソッド分けするのは基本

I temTypeLi st + add()

+ l i nearSearch() + bi narySearch()

(40)

案Ⅱ:ポリモーフィズム

ポリモーフィズムを利用してもできそ うです

I t emTypeBi narySear ch Li st

+ add( ) + sear ch( )

I t emTypeLi near Sear ch Li st

+ add( ) + sear ch( ) I t emTypeLi st

+ add( ) + sear ch( )

(41)

案Ⅲ: アルゴリズムをオブジェクト

アルゴリズムだけをクラスにする方法

Li near Sear ch + sear ch( )

I t emTypeAr r ayLi st + add( )

+ sear ch( ) + di spl ay( )

Bi nar ySear ch + sear ch( )

(42)

さらにポリモーフィズムを使 う

抽象クラスに対してプログラムすれば

、オブジェクトでアルゴリズムの切り 替えが可能になりますね

Li near Sear ch + sear ch( )

Bi nar ySear ch + sear ch( )

Sear chAl gol i t hm + sear ch( )

I t emTypeLi st + add( )

+ sear ch( )

+ di spl ay( ) 11 11

(43)

難しい

それぞれに利点と欠点がある

余裕のある人は、議論してみましょう

参照

関連したドキュメント

第7回 第8回 第9回 第10回

用できます (Figure 2 および 60 参照 ) 。この回路は優れ た効率を示します (Figure 58 および 59 参照 ) 。そのよ うなアプリケーションの代表例として、 Vbulk

第6回赤潮( Skeletonema costatum 、 Mesodinium rubrum 第7回赤潮( Cryptomonadaceae ) 第7回赤潮(Cryptomonadaceae). 第8回赤潮( Thalassiosira

(平成 28 年度)と推計され ているが、農林水産省の調査 報告 14 によると、フードバン ク 45 団体の食品取扱量の合 計は 4339.5 トン (平成

その上で、第一地区、第二地区、第三地区とあるなか、今回の第一地区がその3つの地

全ての人にとっての人権であるという考え方から、国連の諸機関においては、より広義な「SO GI(Sexual Orientation and

シュラウド 補修工事終了 再循環系配管 補修工事予定 シュラウド 補修工事終了 再循環系配管 補修工事中. シュラウド