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

線形探索

N/A
N/A
Protected

Academic year: 2021

シェア "線形探索"

Copied!
48
0
0

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

全文

(1)

「アルゴリズムとデータ構造」資料

3

線形探索と二分探索

鴨浩靖

20091020日 初版 20111011日 第二版 20131011日 第三版 20181029日 第四版

1 / 48

(2)

線形探索

探索範囲の端から順にみつけたいものと比較することを、みつか るか終端に達するまで繰り返すアルゴリズムを、線形探索と呼ぶ。

探索範囲の要素の並び方に制約はない。

2 / 48

(3)

線形探索の動作の例

11を探す [1/5]

11,17

17 2 19 11 23 5 7 13 3 29

3 / 48

(4)

線形探索の動作の例

11を探す [2/5]

11,2

17 2 19 11 23 5 7 13 3 29

4 / 48

(5)

線形探索の動作の例

11を探す [3/5]

11,19

17 2 19 11 23 5 7 13 3 29

5 / 48

(6)

線形探索の動作の例

11を探す [4/5]

11=11

17 2 19 11 23 5 7 13 3 29

6 / 48

(7)

線形探索の動作の例

11を探す [5/5]

みつけた!

17 2 19 11 23 5 7 13 3 29

7 / 48

(8)

線形探索の動作の例

12を探す [1/12]

12,17

17 2 19 11 23 5 7 13 3 29

8 / 48

(9)

線形探索の動作の例

12を探す [2/12]

12,2

17 2 19 11 23 5 7 13 3 29

9 / 48

(10)

線形探索の動作の例

12を探す [3/12]

12,19

17 2 19 11 23 5 7 13 3 29

10 / 48

(11)

線形探索の動作の例

12を探す [4/12]

12,11

17 2 19 11 23 5 7 13 3 29

11 / 48

(12)

線形探索の動作の例

12を探す [5/12]

12,23

17 2 19 11 23 5 7 13 3 29

12 / 48

(13)

線形探索の動作の例

12を探す [6/12]

12,5

17 2 19 11 23 5 7 13 3 29

13 / 48

(14)

線形探索の動作の例

12を探す [7/12]

12,7

17 2 19 11 23 5 7 13 3 29

14 / 48

(15)

線形探索の動作の例

12を探す [8/12]

12,13 17 2 19 11 23 5 7 13 3 29

15 / 48

(16)

線形探索の動作の例

12を探す [9/12]

12,3 17 2 19 11 23 5 7 13 3 29

16 / 48

(17)

線形探索の動作の例

12を探す [10/12]

12,29 17 2 19 11 23 5 7 13 3 29

17 / 48

(18)

線形探索の動作の例

12を探す [11/12]

17 2 19 11 23 5 7 13 3 29

18 / 48

(19)

線形探索の動作の例

12を探す [12/12]

なかった!

17 2 19 11 23 5 7 13 3 29

19 / 48

(20)

線形探索の素朴な実装例

#include <stdlib.h>

int *

search_key(int array[], size_t size, int key) {

size_t i;

for (i = 0; i < size; i ++) { if (array[i] == key)

return &array[i];

}

return NULL;

}

20 / 48

(21)

線形探索の計算量

見つからなかった場合

引数sizeの値をnとして、この関数の実行時間を見積る。

みつからなかった場合の計算時間は、

a(n+1)+bn+c1n+c2 と見積もることができる。ただし、

a 添字の比較1回あたりの計算時間 b 要素の比較1回あたりの計算時間

c1 ループの中でのその他のもろもろの処理1回あたり の計算時間の計

c2 その他のもろもろの処理に必要な計算時間の計 たいていの場合、a,b,c1,c2とも、データによらず、ほぼ一定と みなして良い。

21 / 48

(22)

線形探索の計算量

見つかった場合

引数sizeの値をnとして、この関数の実行時間を見積る。

i要素でみつかった場合の計算時間は、

a(i+1)+b(i+1)+c1i+c2 と見積もることができる。ただし、

a 添字の比較1回あたりの計算時間 b 要素の比較1回あたりの計算時間

c1 ループの中でのその他のもろもろの処理1回あたり の計算時間の計

c2 その他のもろもろの処理に必要な計算時間の計 たいていの場合、a,b,c1,c2とも、データによらず、ほぼ一定と みなして良い。

22 / 48

(23)

線形探索の計算量

最悪計算量

最悪の場合は、見つからなかったとき。

最悪の計算時間は

a(n+1)+bn+c1n+c2 と見積もることができる。

23 / 48

(24)

線形探索の計算量

平均計算量

計算を簡単にするために次のように仮定する。

みつかる確率はαである。

みつかる場合、配列のどの場所もみつかる確率は等しい。

すると、平均の計算時間は、

α n

n−1 i=0

(a(i+1)+b(i+1)+c1i+c2)+(1α)(a(n+1)+bn+c1n+c2) と見積もることができる。

24 / 48

(25)

線形探索の計算量

オーダー

計算すると

最悪計算時間=(a+b+c1)n+a+c2 平均計算時間=(

1 α 2 )

(a+b+c1)n+ α

2(a+bc1)+(1α)(a+c2) 細かい部分には興味ないので、

最悪計算時間 O(n) 平均計算時間 O(n) で良い。

25 / 48

(26)

番兵を使った線形探索の高速化

配列に書き込みが可能な場合は、探索前に探したい値を配列の末 尾に書き込むことで、範囲チェックを省いて高速化できる。

この技法で、末尾に書き込むデータを番兵と呼ぶ。

26 / 48

(27)

番兵を使った線形探索の実装例

#include <stdlib.h>

int *

search_key(int array[], size_t size, int key) {

size_t i;

array[size] = key;

i = 0;

while (array[i] != key) { i ++;

}

return i < size ? &array[i] : NULL;

}

27 / 48

(28)

番兵を使った場合の線形探索の計算量

最悪

引数sizeの値をnとして、この関数の実行時間を見積る。

最悪の場合は、みつからなかった場合。その時の計算時間は、

a+b(n+1)+c1n+c2 と見積もることができる。ただし、

a 添字の比較1回あたりの計算時間 b 要素の比較1回あたりの計算時間

c1 ループの中でのその他のもろもろの処理1回あたり の計算時間の計

c2 その他のもろもろの処理に必要な計算時間の計 c1<c1であるので、番兵を使わない場合よりも比例定数が小さく なって、計算時間は短くなる。

でも、オーダーは変わらない。

28 / 48

(29)

番兵を使った場合の線形探索の計算量 (つづき)

平均

平均計算時間は、同じ仮定の下で、

α n

n1

i=0

(a+b(i+1)+c1i+c2)+(1α)(a+b(n+1)+c1n+c2)

と見積もることができる。

c1<c1であるので、番兵を使わない場合とオーダーは変わらない が、比例定数が小さくなって平均計算時間も短くなる。

29 / 48

(30)

二分探索

探索範囲の真ん中あたりとみつけたいものとを比較し、その結果 によって探索範囲を約半分に縮小することを、みつかるか探索範 囲がなくなるまで繰り返すアルゴリズムを、二分探索と呼ぶ。

探索範囲の要素があらかじめ大きさの順に並んでいることが前提。

30 / 48

(31)

二分探索の動作の例

11を探す [1/7]

2 3 5 7 11 13 17 19 23 29

oo //

31 / 48

(32)

二分探索の動作の例

11を探す [2/7]

11<13

2 3 5 7 11 13 17 19 23 29

oo //

32 / 48

(33)

二分探索の動作の例

11を探す [3/7]

2 3 5 7 11 13 17 19 23 29

oo //

33 / 48

(34)

二分探索の動作の例

11を探す [4/7]

11>5

2 3 5 7 11 13 17 19 23 29

oo //

34 / 48

(35)

二分探索の動作の例

11を探す [5/7]

2 3 5 7 11 13 17 19 23 29

oo //

35 / 48

(36)

二分探索の動作の例

11を探す [6/7]

11=11

2 3 5 7 11 13 17 19 23 29

oo //

36 / 48

(37)

二分探索の動作の例

11を探す [7/7]

みつけた!

2 3 5 7 11 13 17 19 23 29

37 / 48

(38)

二分探索の動作の例

12を探す [1/8]

2 3 5 7 11 13 17 19 23 29

oo //

38 / 48

(39)

二分探索の動作の例

12を探す [2/8]

12<13

2 3 5 7 11 13 17 19 23 29

oo //

39 / 48

(40)

二分探索の動作の例

12を探す [3/8]

2 3 5 7 11 13 17 19 23 29

oo //

40 / 48

(41)

二分探索の動作の例

12を探す [4/8]

12>5

2 3 5 7 11 13 17 19 23 29

oo //

41 / 48

(42)

二分探索の動作の例

12を探す [5/8]

2 3 5 7 11 13 17 19 23 29

oo //

42 / 48

(43)

二分探索の動作の例

12を探す [6/8]

12>11

2 3 5 7 11 13 17 19 23 29

oo //

43 / 48

(44)

二分探索の動作の例

12を探す [7/8]

2 3 5 7 11 13 17 19 23 29

oo//

44 / 48

(45)

二分探索の動作の例

12を探す [8/8]

なかった!

2 3 5 7 11 13 17 19 23 29

45 / 48

(46)

二分探索の実装例

int *

search_key(int array[], size_t size, int key) {

size_t bottom, middle;

for (bottom = 0; size > 0; size /= 2) { middle = bottom + size / 2;

if (array[middle] == key) return &array[middle];

if (array[middle] < key) {

bottom = middle + 1; size --;

} }

return NULL;

}

46 / 48

(47)

二分探索の計算量

引数sizeの値をnとして、この関数の実行時間を見積る。

1回ループを回るたびに探索範囲が約半分になることに注目する と、探索範囲の幅が1になるまで、およそlog2n回、ループを 回る。

したがって、厳密な式を求めることは困難だが、最悪の計算時間 がO(logn)であることは間違いない。

計算の過程は省略するが、前節までと同じ仮定の下で、平均の計 算時間もO(logn)となる。

47 / 48

(48)

まとめ

線形探索 時間計算量:最悪O(n),平均O(n)

探索範囲の要素の並び方に制限はない。

逐次アクセスのみで可。

二分探索 時間計算量:最悪O(logn),平均O(logn)

探索範囲の要素が大きさの順に並んでいる必要 あり。

ランダムアクセスが必要。

48 / 48

参照

関連したドキュメント

について最高裁として初めての判断を示した。事案の特殊性から射程範囲は狭い、と考えられる。三「運行」に関する学説・判例

A number of qualitative studies have revealed that Japanese railroad enthusiasts have low self-esteem, are emotionally distant from others, and possess

 Schwann氏細胞は軸索を囲む長管状を呈し,内部 に管状の髄鞘を含み,Ranvier氏絞輪部では多数の指

 調査の対象とした小学校は,金沢市の中心部 の1校と,金沢市から車で約60分の距離にある

絡み目を平面に射影し,線が交差しているところに上下 の情報をつけたものを絡み目の 図式 という..

荒天の際に係留する場合は、1つのビットに 2 本(可能であれば 3

い︑商人たる顧客の営業範囲に属する取引によるものについては︑それが利息の損失に限定されることになった︒商人たる顧客は

夜真っ暗な中、電気をつけて夜遅くまで かけて片付けた。その時思ったのが、全 体的にボランティアの数がこの震災の規