アルゴリズムとデータ構造 -...

53
アルゴリズムとデータ構造 講義スライド 2 ソートとサーチ 茨城大学 工学部 知能システム工学科 井上 康介 E2棟801号室

Upload: others

Post on 16-Jul-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

アルゴリズムとデータ構造講義スライド 2

ソートとサーチ

茨城大学 工学部 知能システム工学科 井上 康介

E2棟801号室

Page 2: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

第3章:ソートとサーチ

大量のデータを扱うために必要な基本的作業として,ソート (sort:整列) とサーチ (search:探索) がある.

ソートとは,多数のデータ列をある規則に従って並べ替えることを言う.

昇順 (正順):小さい順,降順 (逆順):大きい順

内部ソート:コンピュータのメモリ上のデータを扱う

外部ソート:ハードディスクなどの,外部記憶装置に存在するデータを扱う (本講義では扱わない)

この章では,基本的なソート法を学ぶ.より高速なクイック・ソートとヒープソートは後の章で学ぶ.

要する計算量がp.119の表 3.1にまとめられている.

2

Page 3: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

代表的なソート・アルゴリズムの計算量

教科書 p.119 の表 (訂正あり)

3

ソート法 特徴 計算量

基本形

バブル・ソート 隣接2データの交換を繰り返す.交換回数が多い.安定.

O(n2)

直接選択法 数列から最大 (最小) を探す.比較は多,交換は少.安定.

O(n2)

基本挿入法 ソート済み列への挿入を繰り返す.安定.

O(n2)

改良形

クイック・ソート データ列を大小に2分割する操作を再帰的に繰り返す.不安定.

O(nlogn)

ヒープ・ソート 数列をヒープ構造というデータ構造に組み替える.不安定.

O(nlogn)

シェル・ソート データをとびとびの部分列にして基本挿入法を適用.不安定.

O(n1.25)

Page 4: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

第3章:ソートとサーチ

サーチとは,大量の (n個の) データの中から必要なデータを探し出す作業を言う.

大きく分けて,逐次探索法と2分探索法がある.

逐次探索法では, データを先頭から順番に探索する方法.運良くすぐ見つかれば調べる手間は小さいが, 最悪の場合は最後まで見つからず,n 回調べることになる.データ数が n であれば,要する計算量は O(n).

2分探索法は, あらかじめソートされたデータ群から探索するとき有効. データを大小2つのグループに半分に分け, 境目よりも小さいなら次は小さい方のグループを, 大きいなら次は大きい方のグループを捜す. 計算量は O(log2n)となる (オーダ評価においては,対数の底は略してもよい.cf. 底変換).

4

Page 5: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

追加項目:ソートの安定性

商品番号 価格

50 1000

30 2000

20 2000

40 2000

10 3000

5

ソートの安定性とは,ソート前のデータ順序を維持するかどうかを言う.

商品番号 価格

10 3000

40 2000

50 1000

20 2000

30 2000

商品番号 価格

50 1000

40 2000

20 2000

30 2000

10 3000

元データ

これを価格でソートするとき…

安定

不安定

順序維持

維持せず

高速なアルゴリズムほど不安定となる傾向がある

Page 6: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

直接選択法 (選択ソート法)

最初に直感的に思いつく方法:直接選択法

全体の中で最も小さい数を探し,それを1番目の数として確定する.

2番目以降から最も小さい数を探し,それを2番目の数とする.以下同様.

6

1.対象項 i を 0 から n-2 まで移しながら以下を繰返す2. 対象項 i の値を最小値の初期値とする3. i+1 から n-1 項について,以下を繰返す

4. 最小項を探し,その項番号を s とする.5. i 項と s 項を交換する

アルゴリズム (上記手順をコンピュータに分からせる)

プログラミング

Page 7: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

直接選択法 (選択ソート法)

7

80 50 56 30 51 70

1. 対象項 i を 0 から n-2 まで移しながら以下を繰返す2. 対象項の値を最小値の初期値とする3. i+1 から n-1 項について,以下を繰返す

4. 最小項を探し,その項番号を s とする.5. i 項と s 項を交換する

i=0

min = 80503030 50 56 80 51 70

30 50 56 80 51 70

30 50 51 80 56 70

30 50 51 56 80 70

30 50 51 56 70 80

i=1

i=2

i=3

i=4

i=5

0 1 2 3 n-1

s = 013

(i == n-1 となったら終了)

ソース:p.122

j=12345

Page 8: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

直接選択法の計算量

直接選択法は2重ループで実行する.

データ数が n のとき,

i のループ:ソート対象左端 (0~n-2)

n-1 回まわる.

j のループ:minとの比較対象 (i+1~n-1)

i のループ1回につき,n-i-1 回まわる.

比較回数は,

すなわち,直接選択法の計算量のオーダは O(n2).

8

1( 1) ( 2) 2 1 ( 1)

2n n n n

Page 9: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

バブル・ソート

隣接する2つの項を比較し,逆順であればその2項を入れ替えるという作業を,交換対象がなくなるまで繰り返す.

データ数が n であるとき,まず n-1項 (最後) から 第0項に向けて, 隣接データの比較・交換を繰り返す.この結果,第0項に最小値が入る.

これで第0項が確定するので,次の回は n-1項から第1項までで行う.これで第1項に2番目に小さい数が入る.以後, これを繰り返すと全体がソートされる.

Bubble とは「泡」であり,水中を泡が上がっていくように,小さい数が左に寄せられていくことに対する比喩である.

9

Page 10: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

バブル・ソート

10

30 805056 30 7051i=0

0 1 2 3

8030515630

515630 80 7050

j = N-1(=5)4

i=1

i=2

i=3

i=4

30 350 21

565030 70 8051

56 807050

515030 70 805651 56

565030 70 8051

(交換が一度も起こらなかった回で終了しても良い)

ソース:p.123,124

4 5

Page 11: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

バブル・ソートの計算量

バブル・ソートも2重ループで実行する.

データ数が n のとき,

i のループ:比較・交換のソート範囲左端 (0~n-2)

n-1 回まわる.

j のループ:2データ比較の2データ目位置 (n-1~i+1)

i のループ1回につき,n-i-1 回まわる.

比較回数は,

すなわち,バブル・ソートの計算量のオーダは O(n2).

11

1( 1) ( 2) 2 1 ( 1)

2n n n n

Page 12: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

シェーカー・ソート

バブル・ソートの効率を上げる改良版

バブルソートにおいて, 左端に最大値があったとすると,右側から左向きの走査だけでは i のループごとにじりじりと1つずつしか動かない.そこで, 右向き・左向きの走査を交互に行う.

さらにもう一つの改善策がある.

バブル・ソートでは何が何でも全体にわたって比較

しかし, 例えば左側から比較・交換を行ってきた場合,最後に交換した位置が j と j+1 であるとすれば,j+1 から先は既にソート済みである → 以降無視

12

45 30 37 21 56 70 8030 4537 4521 45

Page 13: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

シェーカー・ソート

13

45

21 89 57 45 30 70

0 1 2 5

left =

right =

shift =

0

5

?

21 89 57 45 30 7057 89 8945 30 8970 89

30 1234

4

21 57 30 70 8945 325730

2

21 70 89455730 45 57

2

バブル・ソートに比較して,大幅な効率化

(ただし,計算量のオーダは変わらず O(n2) (定数係数倍))

(「シェーカー」というのは,バーでカクテルを混ぜるやつ)→ 左右に繰り返し動くことの比喩

ソース:p.124, 125

最後の交換位置

ソート対象右端

ソート対象左端

left == right

となったら終了

3 4

Page 14: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

ポインタとは?

C言語を学習する上では,2つの 鬼門がある.

構造体

ポインタ

プログラミングに対する興味を失ってドロップアウトする人の多くが,これら2つが意味不明であることに起因.

一方で,特にデータ構造に関する学習において,この2つは必須事項である.

そこで,プログラミング演習 I ですでに扱った事項だが,本講義でもポインタに関する復習を行っておく.

14

Page 15: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

ポインタとは?

ガイダンス時に説明したとおり,変数のデータはメモリ空間上の特定位置に書き込まれる.その位置をアドレスという.

例えば

int a;

という宣言をすると,メモリ空間上のあいている場所に変数 a を書き込む領域が確保される.(初期化前はでたらめなデータが入っている)

変数を格納した位置 (メモリアドレス) は,プログラムが管理している.

15

メモリ空間

1628884991

a

0x22cd64番地

Page 16: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

ポインタとは?

アドレスは,変数 a に対して &a で表示できる.

16

メモリ空間

1628884991

a

0x22cd64番地

#include <stdio.h>

void main(void)

{

int a;

printf("a=%d, &a=%x¥n", a, &a);

}

a=1628884991, &a=22cd64

(16進数表示)

Page 17: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

612256ea

ポインタとは?

ポインタとは,データを格納したメモリアドレス (右の例では 0x22cd64番地) を格納する変数のことである.

17

メモリ空間

1628884991

a

int a;

int *pt;

pt = &a;

int型へのポインタ変数 pt を宣言

pt に a のアドレスを代入

22cd64

pt

これにより,変数 pt は変数 a のありかを指し示す (pointする) 変数となる!

Page 18: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

ポインタの使い方

ポインタ演算子

&a : a のアドレス

*pt: pt が示す先にある変数の値

ポインタには型がある

指し示す先の変数の型に基づいて指定

18

#include <stdio.h>

void main(void)

{

int a;

int *pt;

pt = &a;

a = 3;

printf("*pt = %d¥n", *pt);

}

*pt = 3

ポインタ pt が a をpoint

a に 3 を代入

(pt = 0x22cd64)

3

apt

Page 19: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

配列とポインタ

例えば,short型 (1要素2バイト) で要素数が3の配列 b があるとする.

各要素のアドレスは「&」演算子を用いて取り出せる.

&b[1] 0x22cd42

では,配列名 b とは何か?

実は b は 配列の先頭アドレスを指し示すポインタ

b と &b[0] は同じ!

したがって,

19

メモリ空間

b[0]

b[1]

b[2]

2バイト

0x22cd40番地

0x22cd42番地

0x22cd44番地

3545

12446

*b

*b

0x22cd40

12446

-7043b+2 0x22cd44※ ポインタに対する加減算

はデータサイズ単位

b[2] と *(b+2) は同じ

Page 20: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

分かってないとこの講義にはついていけない!

例えば教科書 p.285 の図 6.6 などをみてください.

そこに描かれた3連結された長方形は,構造体です.

そこに描かれた黒丸と矢印は,ポインタです.

つまり…

C言語の鬼門と呼ばれる「構造体」および「ポインタ」が分からないと,この授業を絶対に理解できません.

教科書やウェブサイトを参考にして,すぐ,理解しておいてください.できれば今日・明日中 (忘れるから).分からなければ,次回講義までに友人や井上に聞くこと!

Web上には様々な参考サイトがあり,本屋や図書館にはさまざまな参考図書があります.

20

Page 21: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

レコード型のソート

レコード型データ:フィールド と呼ばれる要素的データの組み合わせから構成されるデータ.

C言語による実装では,構造体 を使って実現する.

21

名前

年齢

職業

名前

年齢

職業

レコード フィールド

構造体 メンバ変数

Page 22: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

レコード型のソート

レコード型データでは,「名前」「年齢」「職業」「電話番号」など,様々なフィールドがある.

このうちの特定のデータ (例えば年齢) を基準としてソートすることを考えるわけだが,その基準となるデータをキー (key) と呼ぶ.

例えば「年齢をキーとしてソートする」などという.

レコード型データをソートする場合,レコード全体を交換しようとすると,複数のフィールドをまとめて交換しなければならないので,手間がかかる.

そこで,各レコードデータへの ポインタの配列 を使ってソートを行う.

22

Page 23: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

レコード型のソート

そのままデータ交換を行うと…

フィールドデータそれぞれを全て交換するので手間がかかる,つまり,効率が悪い.

具体的には,一時待避のためのレコードを用意して,その名前欄,年齢欄,職業欄にそれぞれ片方のデータをコピーし,もう一方のデータを先のデータに上書きコピーした後,待避しておいたデータを元に戻す.

23

メモリ空間Kousuke Inoue

40

Teacher

Taro Yamada

21

Student

Akira Tanaka

29

Athlete

Nobuyo Ooyama

70

レコードの配列

Page 24: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

レコード型のソート

交換の効率を上げるには…

各レコードのアドレスを指し示すポインタの配列を作り,そのポインタを交換する.

交換は,アドレスの書き換えで一発.

24

Kousuke Inoue

40

Teacher

Taro Yamada

21

Student

Akira Tanaka

29

Athlete

Nobuyo Ooyama

70

ポインタの配列

レコードの配列

Page 25: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

構造体へのポインタの使い方

ソースコードを見る準備

構造体 st があって,

struct girl st;

struct girl *pt;

pt = &st;

とする.

構造体 st 内の名前データ:st.name (構造体のメンバの参照方法) printf(“%s”, st.name); とか.

では,これを pt を使って表現するとどうなるか.

pt->name

これで参照できる.これは,(*pt).name と同じ意味.

25

0x41

0x6e

0x6e

0x00

'A'

'n'

'n'

¥0

st.nameaaa

st.age (18)

stpt文字列=char型配列

Page 26: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

レコード型のソート:ソースコード

ソースコード (p.127) を見てみよう.

配列 a[] には,レコード群が格納されている.

配列 p[] には,各レコードへのポインタ群 (各レコードのアドレス) が格納される (最初のfor文).

このコードでは, 名前をアルファベット順に並べている.つまり,キーは名前 (文字列:文字コード (char型) の配列) である.

文字列の大小比較:strcmp() という関数で行う.

26

int strcmp(char *s1, char *s2);

s1, s2:文字列 (char型配列の先頭アドレス)引数:

返値: s1 が s2 に較べて 1)小さい,2)等しい,3)大きい場合に,ゼロよりも 1)小さい,2)等しい,3)大きい整数を返す.

※ C言語の関数をネットで調べる:Googleで,“C言語 strcmp" など

Page 27: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

レコード型のソート:ソースコード

最初の for文で,p[i]=&a[i]; とすることで,レコードa[i] へのポインタ が p[i] に記録される.

次の for文は直接選択法 における対象項 iを回す.

「ここまでの最小値」minを最初の項で初期化.minには名前欄の文字列へのポインタが代入される (「文字列」とは char型変数 (文字コード) の配列である).

jのループで最小値を検索.strcmp()により文字列の大小比較を行い,minよりさらに前に来るべき文字列を見つけたら minとsを更新.jのループを抜けると最小値の番号がsに入っている.

交換は,ポインタ変数tをバッファ (一時避難場所) に使ってポインタ同士の入れ替えを行っている.

27

Page 28: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

基本挿入法 (挿入ソート)

既にソートされた要素の部分列に対して,その次の要素を適切な位置に挿入するという手順を繰り返す.挿入手順は,右から左へ向けた走査 (比較・交換の繰り返し) で実現.

28

80 50 56 30 51 718050

56 30 51 718050 56 80

30 51 7150 56 8030 8030 5630 50

51 71805630 50 51 56 80

7130 50 51 56 8071 80

51

i = 1

i = 2

i = 3

i = 4

i = 5

j = 0

j =

j =

10

210

j = 312

j = 43

交換が起こらなかったらそこで次のループへ

Page 29: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

基本挿入法の計算量

基本挿入法では,ソート済み部分列 (青下線) に次の要素(黒三角) を挿入する手順を繰り返す.

挿入手順は「挿入データの左隣との比較・必要なら交換」を交換の必要がないデータまで繰り返す.以下の場合,比較回数は 3回.

必要とされる比較回数は,挿入対象データの位置 (iとする) に対して,最小で 1回,最大で i回.

最小となるのは,もとからデータが昇順の場合で,このとき毎回比較は1回ですむ.逆に最大となるのは降順のときで,毎回 i回となる.ランダムなら平均的に (i / 2) 回.

50 56 80 30 51 71

50 56 80 30 51 7130 8030 5630 50

29

Page 30: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

基本挿入法の計算量

したがって,比較回数は以下のとおり:

最良の場合 (最初から昇順):

1・(n-1) = n-1 O(n)

最悪の場合 (降順):

1+2+3+…+(n-1) = n(n-1)/2 O(n2)

ランダム列の場合 (期待値):

(1/2)+(2/2)+(3/2)+…+(n-1)/2 = n(n-1)/4 O(n2)

結論として,基本挿入法にとって都合のいい状況 (最初から昇順:この場合ソートする意味が無い) では,O(n) となるが,平均的 (ランダムなデータ列を仮定) および最悪の場合 (降順データ列) では,O(n2) である.

30

Page 31: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

シェル・ソート

基本挿入法の改良バージョン

基本挿入法では,挿入するデータの大小で効率が変わる.

そこで,「おおざっぱでいいから,あらかじめ小さめの値は前方に,大きめの値は後方に振り分けておくと,ソートが速くなる」ということになる.

このために,元データをある間隔 (gap) でとびとびにしたものを集めて,そのグループでソートしておく.

シェル (Shell) は「殻」ではなく,発案者の名前.

31

10 20 30 40 60 506050

10 30 40 50 60 206020502040203020

Page 32: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

シェル・ソート

元のデータをgap のある部分数列に分け,それぞれを基本挿入法でソート,終わったらgap をせばめる.

基本挿入法 (最初から gap=1 のシェル・ソートと等価) と移動の手間を比較すると,全体を通じて基本挿入法では交換回数は17回.それに対してシェル・ソートでは11回.

32

51 60 80 30 45 70 55 21gap = 8/2 = 4 51 80 3045 55 21

60 7051 80 3045 55 21gap = 4/2 = 2(教科書 p.131に誤植)

51 55 60 703021

8045 51 55 60 703021gap = 2/2 = 1 7021 45 55 60 805130

データ数が多いととんでもない差になる (後で見る)

Page 33: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

シェル・ソート

ソースコード:p.132

gapをN/2で初期化して,while文の中でgapごとのソートが終わると gap=gap/2; として繰り返す.

最初のfor文は,特定のgapを持つ数列をずらしている.

次のfor文は,挿入対象を次々と選んでいく.

最後のfor文は,挿入対象を数列に挿入していく.gap

で飛ばした処理をしている点に注意.

p.133 の gapの選び方は重要.gapの系列は互いに素になるように選ぶのが効率がよいとされているが,

…121,40,13,4,1

という数列なら簡単に作れて効率も良くなる.この場合,次のgapは (前のgap)/3 で得られる.

33

Page 34: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

シェル・ソートの計算量と安定性

シェル・ソートの計算量は,平均的には約 O(n1.25) であると予想されている (gap 系列に依存). しかしその導出はきわめて難しく,まだ完全な解析はなされていない.

ランダムに生成した50000 個のデータに対して特定のコンピュータで実行した実行時間の例によると,基本挿入法よりも圧倒的に速い.

シェル・ソートは不安定 である.その理由は,複数の同じ数字があったとき,それらが別の部分数列に所属してしまう可能性 (よって,追い越しの可能性) があるからである.

34

基本挿入法 13.11秒

シェル・ソート 0.09秒

Page 35: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

逐次探索 (sequential search)

ソートに続いて,サーチの内容に入る.

サーチとは,たくさんのデータから目標とするデータを発見する作業である.

逐次探索 (または,線形探索 (linear search)) では,配列などに格納されたデータを先頭から1つずつ順に調べて,見つかればそこで探索を中止する.

レコードのデータの配列については,そのうちの特定のフィールド (例えば「名前」) を キーとして,与えられたキーに合致するフィールドを持つレコードを発見すればよい.

計算量は O(n).

ソースコード: p.135-136.

35

Page 36: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

番兵を立てる

先程の逐次探索のコードでは,探索している視点を動かしていくループにおいて,

while (i < N && strcmp(key,a[i].name)!=0) i++;

としていた.つまり,「見ている番号 i が N に達したかどうかの判定」と, 「キーとデータが一致したかどうかの判定」の 2つを行っている.

一番最後のデータの後ろに更に1つ余分な要素を追加し,ここにキーと同じデータを加えておくと…

i と N との大小比較をしなくても,最後の余分なデータに到達すれば探索が終了してくれるので, 余分な条件判定が不要となり,若干の高速化が望める (条件判定は多少時間がかかる仕事である).

この目的で最後に追加するデータを 番兵 (sentinel) と呼ぶ.

36

Page 37: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

ソース・コード (p.137) の補足

関数 strcpy() について

プロトタイプ:

char *strcpy(char *s1, char *s2);

ポインタ s1 で与えられるアドレスに,

ポインタ s2 から先に並ぶ文字データの列をコピーする.

null文字 (文字列の終端の記号.‘¥0’ と表記し,数としてはゼロ) をコピーし終わったら終了する.

戻り値:s1 (コピーした文字列へのポインタ)

37

0x41「A」

0x6e「n」

0x6e「n」

0x00「¥0」

0x41「A」

0x6e「n」

0x6e「n」

0x00「¥0」

s1

s2

Page 38: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

2分探索 (binary search)

2分探索:データがソート済みで,昇順または降順に並んでいるときに,効率よく探索を行うアルゴリズム.

基本的には,数値計算において学んだ非線形方程式を解くための2分法と同じで,探索範囲を絞っていく方法.

教科書 p.141 の図を参照.

探索する対象の上限を upper,下限を low とする.

上限と下限のちょうど真ん中の位置 x において,データの値がキーと等しいなら発見.キーより大きいときは, 探索対象は lower と x-1 の間にあるので,upper=x-1

として下半分を探す.逆の場合は探索対象は x+1 とupper の間.そこで lower=x+1 として上半分を探す.

38

Page 39: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

2分探索 (binary search)

終了条件

中央の位置 xに探すデータがあれば発見.

探索範囲の下限 lowと上限 upperが入れ替わったら,対象データはないので終了.

教科書のミス:

p.141では探索範囲の下限・上限・中央がそれぞれ,low, upper, xとなっているが,p.142では,ソースコードを含めてこれらが low, high, midとなっている.

計算量は O(logn).最悪でも log2n 回の繰り返しで終了するので.平均はその定数倍.

39

Page 40: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

2分探索の計算量

2分探索では,1回の処理ごとに検索対象データが半分になる.最悪の場合,検索対象データは1データまで減少し,そこで発見または不在が判明する.

1データ

1回目

2回目

3回目

h回目

nデータ

40

Page 41: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

2分探索の計算量

h 回目の作業で検索対象データが1データにまで落ちたとすると, が成り立つので, .両辺の対数を取ると, .

(1/2) 1hn 2h n

2logh n

1データ

1回目

2回目

3回目

h回目

nデータ

41

Page 42: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

2分探索の計算量

すなわち,最悪の場合の繰り返し回数が であり,平均的にはその a倍となるから,平均繰り返し回数は

.オーダでは定数係数を無視して,O(logn).

2logh n

2log n

1データ

1回目

2回目

3回目

h回目

nデータ

42

Page 43: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

文字列の照合 (パターンマッチング)

元の文 text の中から照合するキー文字列 key を探す.

ソースコード: p.148-149.

strlen(char *p) は,文字列pの長さを返す関数.

strncmp(char *s1, char *s2, size_t n)は,s1

とs2の最初のn文字だけを比較する点を除けば,strcmp()と同じ.

ただし,size_t型は,実体は unsigned int型と同じで,変数のサイズ (バイト数) を表すのに使う.

関数search()において,探す位置のポインタpを1つずつずらしながら文字列の照合を行っている. 最後まで見つからないときはNULLポインタを返す.

43

Page 44: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

Boyer-Moore法

先程の,1文字ずつずらしていく方法では効率が悪い.とばせるところはとばすという方法が考えられる.

44

T h i s i s a p e n .c i ltext

p

p e n c i lkey

合致していないとき,従来版:一つずらす

Boyer-Moore法:ずらす量を決める

p e n c i l

ずらし量の基準:キーの右端位置のtext中の文字

p e n c i lp e n c i l

このために,文字ごとに進める量の表を作っておく:l なら6文字,i なら1文字,c なら2文字…

※ 同じ文字が複数あるときは?

Page 45: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

ハッシュ (hash)

探索を高速化するための技法で,幅広く使われている.

例えば住所録から人名をキーとして探索を行う場合,ありうる人名はきわめて多数.

ハッシュ (hash) という技法で,探索が一気に早くなる.

ある多対一写像を使って,「人名0~999の数」という対応関係 を作る.

それぞれの個人データをサイズ 1000の配列の中の当該位置に入れておく.

探索時は,探す名前を写像に従って 0~999の数に変換し,配列の当該位置を見に行く.

こうすれば,探索はデータ数によらず一定時間でできる.

O(1).

45

Page 46: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

ハッシング (hashing)

ハッシング (hashing):キー (この場合, 人名) を限られた数値範囲 (この場合, 0~999) に写像することを言う.

写像の作り方は問題に応じてどうやってもよい.

次ページは教科書の例.ただし別にこの方法にこだわる必要はない.

46

Page 47: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

キーが英字の大文字からなる名前とし,A1, A2, …,An のn 文字からなるものとすると,この場合,あり得る名前は26n 通り存在する.これは膨大な範囲である.

これを 0~999 の限られた範囲に縮退するには,例えば

という関数による写像を行う.すると,名前が 0~999の数字のいずれかに変換 (写像) される.

例えば "SUZUKI" さんの場合,

hash(A1, A2,…, An)=(A1 + An/2×26 + An-1×262) % 1000

ハッシング (hashing) の例

47

hash("SUZUKI")=(('S'-'A')+('Z'-'A')*26+

('K'-'A')*26*26) % 1000

=(18+650+6760) % 1000 = 428

※ 例えば 'S' は大文字の "S" の文字コード (83) のこと

Page 48: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

ハッシュ (hash)

このようなハッシュ処理によって,"SUZUKI" さんの名前が 428 という数に写像された.

48

INOUE

KOBAYASHI

TANAKA

6102

425

999

キーの集合数値集合(0~999)

番号 キー 年齢

0

1

2 KIKUCHI 21

… …

427 YAMADA 40

428 SUZUKI 28

… …

999

SUZUKI428

逐次探索:O(n) → ハッシュ:O(1)

ハッシュテーブル

Page 49: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

ハッシュ (ソースコード)

p.158-159.

ハッシュの写像の実体は関数 int hash(char *s).ここで文字列 sを数に変換して返値として返す.

データの表は構造体の配列 struct tel dat[].

main関数では,最初に表の中身を作っている.

while (scanf("%s %s",a,b)!=EOF) という条件文により,aと bを何回もユーザ入力してもらう.

ユーザが終了信号 Ctrl+Z を押すと,scanf() が EOF

(end of file) という信号を返し,while文を抜ける.

while文の中では,文字列a (名前) を数nに写像し,データ表の第n要素に名前と電話番号を記入している.

49

Page 50: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

ハッシュ (ソースコード)

rewind(stdin) という処理は,標準入力 (stdin) に残ったデータ (改行文字) を取り除く.

scanf() でユーザが入力を行うとき,例えば "SUZUKI" と入れた後に, それを確定する意味で改行 (リターンキー) を入れる. この改行文字まで含めて読み込まれてしまうと面倒なことになることがある.

そこで, ユーザからの入力が入る 標準入力ストリーム(stdin)に残っている文字をいったん全部消してしまう操作をする.

(おそらく一般的な処理系では,この操作は必要ない.)

次の while文でも,ユーザから繰り返し入力を受ける.

名前を入れるとその名前をハッシュ処理して数に写像し,その数に対応するハッシュテーブル要素を見に行く.

50

Page 51: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

問題:かち合い

名前の種類は無数にあり,それを1000程度の小さな値の範囲に写像しているので,当然 1対1 対応ではない.

異なる名前が同じ値になる場合をかち合い (collision) と呼ぶ.先程の方法では“ANZAI”も“SUGIYAMA”も 338.

一つの安直な方法は,既に338 にANZAIさんのデータが記録されていた場合,SUGIYAMAさんのデータは 339番以降の空いている場所に書き込む (教科書 p.160の図).

1000番以降の,本来使わない領域も多少領域をキープしておけば,この方法で記録できる.

データを検索する場合は,まずは338 番を見に行き,そこに書かれたデータがSUGIYAMAさんのものではなかったら,次以降を逐次探索する.

51

( このせいで,結局 O(n))

Page 52: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

問題:かち合い

ただ,この方法では,ハッシュテーブルが詰まってくると,空のテーブルがなかなか見つからず,かなり遠いところまで逐次探索で探しに行くことになり,効率が悪い.

このようにハッシュテーブルに直接データを格納する方法を オープンアドレス法 と呼ぶ.

ソース・コード:p.160 (ミス:empty フラグ初期化忘れ)

これに対して,リスト構造 (第5章) を用いた別の方法が考えられる.これをチェイン法 と呼ぶ.

チェイン法では,ハッシュテーブルにANZAIさんのデータをそのまま格納するのではなく,ANZAI さんのデータへのポインタ (データのアドレス) を記入しておく.

探索時は,対応するハッシュテーブルに書かれたアドレスを見に行けばよい.

52

Page 53: アルゴリズムとデータ構造 - Ibarakibiorobot2.ise.ibaraki.ac.jp/inoue/ad/material/slide-2.pdfアルゴリズムとデータ構造 講義スライド2 ソートとサーチ

チェイン法によるハッシング

リスト構造とは,データを格納する構造体に,「次のデータ」へのポインタを取り付けてデータ同士をつないでいく方法である.

探索時は,対応するリスト要素を逐次探索していく.

53

ANZAI

ハッシュテーブル

0

999

338 SUGIYAMA

リスト要素 リスト要素

次のデータへのポインタ(最後尾にはNULLポインタ)

年齢や電話番号などのデータ

( O(n))

ここに SUGIYAMA さんのデータを追加するには…

まだ記録されていない番号にはNULLポインタ