Post on 12-Aug-2020
2017/04/18 アルゴリズムとデータ構造
1
アルゴリズムとデータ構造
第4回基本的なデータ構造(ヒープ)
再帰的アルゴリズム
アルゴリズムとデータ構造 20152015/11/04
2
リスト
•リストとは要素を0個以上1列に並べたもの
•リスト a0,a1,…,an-1の実現法
1. 配列(array)
2. 連結リスト(linked list)
3. 双方向連結リスト(doubly linked list)
a0 a1 ・・・ an-1
an-1 nulla1a0init ・・・
an-1 nulla1a0init ・・・null ・・・ final
前回の復習(1/3)
•配列はi番目の要素への位置付けが容易、(双方向)連結リストは挿入・削除が容易
i番目の要素への位置付け挿入 or 削除
配列 (双方向)連結リストO(1) O(n)O(n) O(1)
アルゴリズムとデータ構造 20152015/11/04
3
リストの応用
•スタック
前回の復習(2/3)
要素の挿入、削除がいつも先頭からなされるリストLIFO(last-in-first-out)
a0
a1
a2 PUSH(a2,S)
a0
a1
a2
a0
a1
a2POP(S)
TOP(S)
•待ち行列(キュー)要素の挿入は最後尾、削除は先頭からなされるリストFIFO(first-in-first-out)
a0 a1 a2ENQUEUE(a2,Q)
a0 a1 a2
TOP(Q)
a0 a1 a2
DEQUEUE(Q)
pr oc PUSH( x: el ement t ype; var S: st ack) ;
begi n
i f S. t op : = 1 t hen
wr i t el n( "ERROR! ") ;
el se begi n
S. t op : = S. t op - 1;
S. el ement [ S. t op] : = x;
end
end .
E
B
A
F
C
D
10
9
8
7
6
5
4
3
2
1
el ement
5
t op
補足:配列によるスタックの実現
アルゴリズムとデータ構造 20152015/11/04
5 前回の復習(3/3)
・・・ ・・・a0
j
すべての操作の時間計算量はO(1)
キューの配列による実現front
Q
TOP(Q)
ENQUEUE(ai+1,Q)
ai ・・・
=
(j+i)%nrear0 n-1
DEQUEUE(Q)
a1
・・・ ・・・a0
front
Q ai ・・・
(j+i+1)%nrear0 n-1
a1 ai+1
・・・ ・・・
(j+1)%nfront
ai ・・・
(j+i+1)%nrear0 n-1
a1 ai+1
j
Qバリエーション
•rearを最後尾の次のインデックスとする。
•rearを保持せずに要素数numを保持し、rearは毎回(front+num-1)%nで計算しなおす。
「空(カラ)」か「空きなし」かの判断は?
・要素数numを保持する場合はnum=0であれば空(カラ)、num=nであれば空きなし。
・要素が入っていない状態を表す特別な値(要素として現れない値)で配列を初期化し、
DEQUEUEのときに取り出した位置を初期化する。ENQUEUEの時、追加しようとした
位置に要素が格納されていれば空きなし。
・要素の数をn-1までしか格納しない。rear=(front-1)%nであれば「空(カラ)」、
rear=(front-2)%nの場合には「空きなし」と判断する。
A4 A5 A1 A2 A3
0 1 2 3 4 5
frontrear
配列で巡回リストを表わす. キューの長さ n が限定された場合
先頭と末尾がつながって,輪になったリスト
要素の位置を,n の剰余演算で決定.
補足:配列によるキューの実現
front から i 番目の要素 = Element[ (front + i) mod n ]
Element
ex. Elem[(head + 5) mod n] (head = 1 and n = 6)= Elem[7 mod 6] = E[1]
A
F
CB
ED
10987654321
element
3front
7rear
配列によるキューの実現
優先度つき待ち行列応用
要素間に全順序≦が定義されている集合A.
Priority Queue の単純な実現方法
〜連結リスト(linked list)を用いる方法
整列しない場合
DELETEMIN( A )O( n ) 時間先頭から操作し,最小の要素をみつける.
INSERT( x, A )O( 1 ) 時間先頭に挿入するだけ.
あらかじめ整列した場合
DELETEMIN( A )O( 1 ) 時間先頭の要素を除くだけ
INSERT( x, A )O( n ) 時間先頭から操作し,順序を保って挿入する.
Header
a2 . . . ana1
DELETEMINとINSERTの両方の演算を
もっと効率良く実現できないか?
アルゴリズムとデータ構造 20152015/11/04
11
疑問
ヒープ (heap)
ヒープ(heap)
アルゴリズムとデータ構造 20152015/11/04
13
英語:「山積み」という意味.
アルゴリズムとデータ構造 20152015/11/04
14
優先度付き待ち行列(ヒープ, heap)集合X上の全順序(total order, 線形順序(linear order))とは
X上の要素間の2項関係`≦’で、次の性質をもつものをいう。
(1) x≦x for all x∈X (反射律, reflexivity)(2) x≦y, y≦z ⇒ x≦z (推移律, transitivity)(3) x≦y, y≦x ⇒ x=y (反対称律, anti-symmetry)(4) x≦y or y≦x for all x,y∈X (比較可能性, comparability)
全順序`≦’が定義されている集合の要素を節点にもつ木で次のような条件を満たす2分木(各節点の子の数が高々2つの木)を考える。
ヒープ条件
任意の節点uに対して
uの親の要素≦uの要素
が成り立つ。
2
5 8
7 10 11 9
10 11 12
* 初心者注意
アルゴリズムとデータ構造 20152015/11/04
15
ヒープの定義
ヒープ(heap, 順位付きキュー(priority queue))とは
A[i]の親をA[ (i-1)/2 ]として定義される2分木がヒープ条件を満たす配列A
i i+1 i+2i-1i-2
xx xyy y= =
2
5 8
7 10 11 9
10 11 12
(例) 2 5 8 7 10 11 9 10 11 12
2
5 8
7 10 11 9
10 11 12
0 1 2 3 4 5 6 7 8 9
0
1 2
3 4 5 6
7 8 9
アルゴリズムとデータ構造 20152015/11/04
16
ヒープの定義
ヒープ(heap, 順位付きキュー(priority queue))とは
A[i]の親をA[ (i-1)/2 ]として定義される2分木がヒープ条件を満たす配列A
i i+1 i+2i-1i-2
xx xyy y= =
2
5 8
7 10 11 9
10 11 12
(例) 2 5 8 7 10 11 9 10 11 12
2
5 8
7 10 11 9
10 11 12
0 1 2 3 4 5 6 7 8 9
0
1 2
3 4 5 6
7 8 9
アルゴリズムとデータ構造 20152015/11/04
17ヒープの基本操作(最小要素の削除)
DELETEMIN(A) 最小(根にある)要素の削除 (n:削除前の要素数)Step 1 A[0]←A[n-1], i←0Step 2 2i+1≧n-1ならば停止。
そうでなければj←argmink∈{2i+1,2i+2},k<nA[k]とする。
Step 3 A[i]≦A[j]ならば停止。
そうでなければA[i]とA[j]の中身を入れ替え、i←jとしてStep 2へ実行例
12
5 8
7 10 11 9
10 11
i
Step 1
2
5 8
7 10 11 9
10 11 12
12
5 8
7 10 11 9
10 11
i
Step 2
j 5
12 8
7 10 11 9
10 11 Step 3
i
5
12 8
7 10 11 9
10 11 Step 2
i
j
5
7 8
12 10 11 9
10 11 Step 3
i
5
7 8
12 10 11 9
10 11 Step 2
i
j
5
7 8
10 10 11 9
12 11 Step 3i
Step 2停止
アルゴリズムとデータ構造 20152015/11/04
18ヒープの基本操作(要素の追加)
INSERT(x,A) 要素の追加 (n:追加前の要素数)Step 1 A[n]←x, i←nStep 2 i=0ならば停止。
そうでなければj← (i-1)/2 とする。
Step 3 A[i]≧A[j]ならば停止。
そうでなければA[i]とA[j]の中身を入れ替え、i←jとしてStep 2へ実行例
2
5 8
7 10 11 9
10 11 i
Step 12
5 8
7 10 11 9
10 11 12
2
5 8
7 10 11 9
10 11
Step 2
j
2
5 8
7 4 11 9
10 11
Step 3
2
5 8
7 11 9
10 11
Step 2j2
8
11 9
Step 32
8
11 9
Step 2Step 3停止
12 4 i12 4 12 10
i
4
12 10
i4
7
10 11
5
12 10
i4
7
10 11
5
12 10
ij
アルゴリズムとデータ構造 20152015/11/04
19
ヒープの基本操作の時間計算量
DELETEMIN(A), INSERT(x,A)ともに、各Stepは定数時間で実行可能
Step 2とStep 3の間のループの回数のオーダーで実行可能
1回の繰り返し毎にDELETEMINはiの位置が1つずつ深くなっていくINSERTは iの位置が1つずつ浅くなっていく
最悪、木の高さの回数だけループする
要素数nのヒープを2分木で表現した場合、木の高さは log2n である。
DELETEMIN(A)とINSERT(x,A)の最悪時間計算量はO(log n)
証明してみよう!
* 初心者注意
整列問題の解法:ヒープソート
アルゴリズムとデータ構造 20152015/11/04
23
再帰呼出し
再帰呼出しとは
関数がその定義の中でそれ自身を呼び出すこと
再帰的アルゴリズムとは
再帰呼出しを用いて記述されたアルゴリズム
アルゴリズムとデータ構造 20152015/11/04
24
再帰的アルゴリズムの例
最大公約数を求めるアルゴリズム(ユークリッドの互除法)
gcd(int m,int n){
int r=m%n;if( r=0 ) return n;else return gcd(n,r);
}
2つの自然数m,n(m≧n)の最大公約数はgcd(m,n)
gcd(int m,int n){
if( n=0 ) return m;else return gcd(n,m%n);
}
実はもっと簡潔に以下のようにも書ける。
Euclid(Eukleides)ユークリッド(エウクレィデス)(紀元前300年ごろ)
アルゴリズムとデータ構造 20152015/11/04
25
再帰呼出しを使うことのメリット
•記述が簡潔になる
•理解しやすくなる
•アルゴリズムの正しさの証明がしやすくなる
•計算量の解析が容易になる
アルゴリズムとデータ構造 20152015/11/04
26
再帰的アルゴリズムの作り方
1. 解くべき問題を、同じ問題でよりサイズの小さな問題を解くことに帰着させる。(漸化式を立てる)
例) mとn(m≧n)の最大公約数は、nとm%nの最大公約数と同じ。gcd(m,n)=gcd(n,m%n) for n>0
2. 最小サイズの問題の解を示す。
例) mとn(m≧n)の最大公約数は、m%n=0のときn
数学的帰納法で証明を書くつもりで!
アルゴリズムとデータ構造 20152015/11/04
27
何でも再帰呼出しにすれば良いというもでは・・・
gcd(int m,int n){
int a[2]={m,n}, i=1,j;while(a[i]!=0) {
j=(i+1)%2;a[j]=a[j]%a[i];i=j;
}return a[(i+1)%2];
}
gcd(int m,int n){
if( n=0 ) return m;else return gcd(n,m%n);
}
再帰呼出しを使わないと
×記述は少し複雑○メモリ使用量は少ない
(スタック領域の使用量が少ない)○計算時間も短い
(関数呼出し、復帰処理がない)
関数の最初または最後に1回だけ再帰呼出しされる場合
ループを用いて比較的容易にかける場合が多い
アルゴリズムとデータ構造 20152015/11/04
28
再帰呼出しの時間計算量
再帰的アルゴリズムの時間計算量=
再帰呼出しの時間計算量 + 再帰呼出し以外の時間計算量
プログラム
int factorial(int n) {if(n==1) return 1;else return n*factorial(n-1);
}
(例)
factrial(n)の実行時間をT(n)とおくと
再帰呼出しfactrial(n-1)の時間計算量=T(n-1)
再帰呼出し以外の時間計算量≦C (定数)
よって T(n)≦T(n-1) + C, T(1)≦C
したがって T(n)≦Cn=O(n)
アルゴリズムとデータ構造 20152015/11/04
29
ハノイの塔の演習問題を解いてみよう!
ハノイの塔は、フランスの数学者E・リュカ(Edouard Lucas)が1883年に考えたものである。リュカは、インドに次のような伝説があると説明している。
ブラフマーの塔
インドのガンジス河の畔のベナレス(ヴァラナシ)に世界の中心を表すという聖堂がある。そこには3本の大理石の柱(ダイヤモンドの針との説もあり)が立てられており、そのうちの1本には、当初64枚の黄金の円盤が大
きい円盤から順に重ねられていたという。バラモン僧たちはそこで、一日中円盤を別の柱に移し替える作業を行っている。そして、全ての円盤の移し替えが終わったときに、この世は崩壊し終焉を迎えると言われている。
もちろんこれはリュカの作り話であるが、64枚の円盤を移動させるには、最低でも18,446,744,073,709,551,615回かかり、1枚移動させるのに1秒かかったとして、約5,845億年かかる(なお、ビッグバンは今から約137億年前の発生とされている)。