160 likes | 264 Views
アルゴリズムとデータ構造. 第4回基本的なデータ構造(ヒープ) 再帰的アルゴリズム. 前回の復習 (1/ 3 ). リスト. リストとは 要素を0個以上1列に並べたもの. リスト a 0 ,a 1 ,…,a n-1 の実現法. a 0. a 1. ・・・. a n-1. 1. 配列 (array). 2. 連結リスト (linked list). init. a 0. a 1. ・・・. a n-1. null. 3. 双方向連結リスト (doubly linked list). ・・・. init. null. a 0.
E N D
アルゴリズムとデータ構造 第4回基本的なデータ構造(ヒープ) 再帰的アルゴリズム アルゴリズムとデータ構造 2013
前回の復習(1/3) リスト • リストとは要素を0個以上1列に並べたもの • リスト a0,a1,…,an-1の実現法 a0 a1 ・・・ an-1 1. 配列(array) 2. 連結リスト(linked list) init a0 a1 ・・・ an-1 null 3. 双方向連結リスト(doubly linked list) ・・・ init null a0 a1 an-1 null final ・・・ • 配列はi番目の要素への位置付けが容易、 • (双方向)連結リストは挿入・削除が容易 配列 (双方向)連結リスト O(1) O(n) i番目の要素への位置付け 追加 or 削除 O(n) O(1) アルゴリズムとデータ構造 2013
前回の復習(2/3) リストの応用 • スタック 要素の挿入、削除がいつも先頭からなされるリスト LIFO(last-in-fast-out) a2 a2 PUSH(a2,S) POP(S) a2 TOP(S) a1 a1 a1 a0 a0 a0 • 待ち行列(キュー) • 要素の挿入は最後尾、削除は先頭からなされるリスト FIFO(fast-in-fast-out) ENQUEUE(a2,Q) a0 a1 a2 TOP(Q) a0 a1 a2 DEQUEUE(Q) a1 a2 a0 アルゴリズムとデータ構造 2013
前回の復習(3/3) TOP(Q) キューの配列による実現 = front j rear (j+i)%n 0 n-1 Q ・・・ a0 a1 ・・・ ai ・・・ rear (j+i+1)%n ENQUEUE(ai+1,Q) front j 0 n-1 すべての操作の 時間計算量は O(1) Q ・・・ a0 a1 ・・・ ai ai+1 ・・・ DEQUEUE(Q) rear (j+i+1)%n front (j+1)%n 0 n-1 Q ・・・ a1 ・・・ ai ai+1 ・・・ • バリエーション • 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の場合には「空きなし」と判断する。 アルゴリズムとデータ構造 2013
優先度付き待ち行列(ヒープ, 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つの木)を考える。 2 ヒープ条件 任意の節点uに対して uの親の要素≦uの要素 が成り立つ。 5 8 7 10 11 9 10 11 12 アルゴリズムとデータ構造 2013
i i+1 i+2 i-1 i-2 ヒープの定義 x x x y y y = = ヒープ(heap, 順位付きキュー(priority queue))とは A[i]の親をA[ (i-1)/2 ]として定義される2分木がヒープ条件を満たす配列A 9 8 7 6 5 4 3 2 1 0 (例) 2 5 8 7 10 11 9 10 11 12 0 2 2 1 2 5 8 5 8 3 4 5 6 7 10 11 9 7 10 11 9 10 11 12 7 8 9 10 11 12 アルゴリズムとデータ構造 2013
ヒープの基本操作(最小要素の削除) DELETEMIN(A) 最小(根にある)要素の削除 (n:削除前の要素数) Step 1 A[0]←A[n-1], i←0 Step 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へ 実行例 i i 2 12 12 5 j i 5 8 5 8 5 8 12 8 7 10 11 9 7 10 11 9 7 10 11 9 7 10 11 9 Step 1 Step 2 Step 3 12 10 11 10 11 10 11 10 11 5 Step 2 停止 5 5 5 i 7 8 7 8 7 8 12 8 i i j 10 10 11 9 12 10 11 9 12 10 11 9 7 10 11 9 i j Step 3 Step 2 Step 3 Step 2 12 11 10 11 10 11 10 11 アルゴリズムとデータ構造 2013
ヒープの基本操作(要素の追加) INSERT(x,A) 要素の追加 (n:追加前の要素数) Step 1 A[n]←x, i←n Step 2 i=0ならば停止。 そうでなければj← (i-1)/2 とする。 Step 3 A[i]≧A[j]ならば停止。 そうでなければA[i]とA[j]の中身を入れ替え、i←jとしてStep 2へ 実行例 2 Step 1 Step 2 Step 3 2 2 2 5 8 5 8 5 8 5 8 i j 7 10 11 9 7 10 11 9 7 10 11 9 7 4 11 9 12 10 11 12 4 12 4 12 10 10 11 10 11 10 11 i i j 2 Step 2 Step 3 2 2 j Step 2 i i Step 3 停止 8 4 4 8 5 8 i 11 9 5 5 4 7 7 11 9 7 11 9 12 10 12 10 12 10 10 11 10 11 10 11 アルゴリズムとデータ構造 2013
ヒープの基本操作の時間計算量 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) アルゴリズムとデータ構造 2013
再帰呼出し 再帰呼出しとは 関数がその定義の中でそれ自身を呼び出すこと 再帰的アルゴリズムとは 再帰呼出しを用いて記述されたアルゴリズム アルゴリズムとデータ構造 2013
再帰的アルゴリズムの例 最大公約数を求めるアルゴリズム(ユークリッドの互除法) 2つの自然数m,n(m≧n)の最大公約数はgcd(m,n) Euclid(Eukleides)ユークリッド(エウクレィデス)(紀元前300年ごろ) gcd(int m,int n) { int r=m%n; if( r=0 ) return n; else return gcd(n,r); } 実はもっと簡潔に以下のようにも書ける。 gcd(int m,int n) { if( n=0 ) return m; else return gcd(n,m%n); } アルゴリズムとデータ構造 2013
再帰呼出しを使うことのメリット • 記述が簡潔になる • 理解しやすくなる • アルゴリズムの正しさの証明がしやすくなる • 計算量の解析が容易になる アルゴリズムとデータ構造 2013
再帰的アルゴリズムの作り方 数学的帰納法で証明を書くつもりで! • 解くべき問題を、同じ問題でよりサイズの小さな問題を解くことに帰着させる。 • (漸化式を立てる) • 例) mとn(m≧n)の最大公約数は、nとm%nの最大公約数と同じ。 • gcd(m,n)=gcd(n,m%n) for n>0 • 最小サイズの問題の解を示す。 • 例) mとn(m≧n)の最大公約数は、m%n=0のときn アルゴリズムとデータ構造 2013
何でも再帰呼出しにすれば良いというもでは・・・何でも再帰呼出しにすれば良いというもでは・・・ 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回だけ再帰呼出しされる場合 ×記述は少し複雑 ○メモリ使用量は少ない (スタック領域の使用量が少ない) ○計算時間も短い (関数呼出し、復帰処理がない) ループを用いて比較的容易に かける場合が多い アルゴリズムとデータ構造 2013
再帰呼出しの時間計算量 再帰的アルゴリズムの時間計算量= 再帰呼出しの時間計算量 + 再帰呼出し以外の時間計算量 (例) factrial(n)の実行時間をT(n)とおくと 再帰呼出しfactrial(n-1)の時間計算量=T(n-1) 再帰呼出し以外の時間計算量≦C (定数) プログラム int factorial(int n) { if(n==1) return 1; else return n*factorial(n-1); } よって T(n)≦T(n-1) + C, T(1)≦C したがって T(n)≦Cn=O(n) アルゴリズムとデータ構造 2013
ハノイの塔の演習問題を解いてみよう! • ハノイの塔は、フランスの数学者E・リュカ(Edouard Lucas)が • 1883年に考えたものである。リュカは、インドに次のような伝 • 説があると説明している。 • ブラフマーの塔 • インドのガンジス河の畔のベナレス(ヴァラナシ)に世界の中心を表すという聖堂がある。そこには3本の大理石の柱(ダイヤモンドの針との説もあり)が立てられており、そのうちの1本には、当初64枚の黄金の円盤が大きい円盤から順に重ねられていたという。バラモン僧たちはそこで、一日中円盤を別の柱に移し替える作業を行っている。そして、全ての円盤の移し替えが終わったときに、この世は崩壊し終焉を迎えると言われている。 • もちろんこれはリュカの作り話であるが、64枚の円盤を移動させるには、最低でも18,446,744,073,709,551,615回かかり、1枚移動させるのに1秒かかったとして、約5,845億年かかる(なお、ビッグバンは今から約137億年前の発生とされている)。 アルゴリズムとデータ構造 2013