離散システム特論 整列(sorting)アルゴリズム 1 参考文献 1. 大森克史・木村春彦・広瀬貞樹 著 「アルゴリズム の基礎」 共立出版(1997) 2. 渡邊敏正 著 「データ構造と基本アルゴリズム」 共立出版(2000) 整列とは • 全順序集合Sが与えられたとき,Sのすべて の要素をその全順序に従って並べ替えるこ と. • 簡単のため,n個の整数の集合をSとし,通 常の数字の大小関係で小さい数から大きい 数へ並べ替えるとする(昇順ソート ascending sort). ソーティングアルゴリズム 選択法(selection sort) データ列の最小値を選択し,未整列部分の 先頭に置くことを順次繰り返す. ◆ min{a1, a2, … , an}とa1を交換 ◆ min{a2, …, an}とa2を交換 ... ◆ min{an-1, an}とan-1を交換 選択法の擬似コード for (i=1; i≦n-1;i++){ min:= i; // 最小値の添字をしまう. for (j=i+1; i≦n; j++){ if(aj < amin) min :=j; } swap(ai, amin); } 選択法の例 (4,10,5,2,1,7,9,3,8,6) (1,10,5,2,4,7,9,3,8,6) (1,2,5,10,4,7,9,3,8,6) (1,2,3,10,4,7,9,5,8,6) (1,2,3,4,10,7,9,5,8,6) (1,2,3,4,5,7,9,10,8,6) (1,2,3,4,5,6,9,10,8,7) あとはよろしく 選択法の計算量 n個のデータのソートに必要な最悪比較回数 for (i=1; i≦n-1;i++){ min:= i; // 最小値の添字をしまう. for (j=i+1; i≦n; j++){ if(aj < amin) min :=j; } swap(ai, amin); } O( ? ) バブルソート(bubble sort) 隣接する2項を比較し,aj > aj+1のように左の項が 右の項よりもおおきければ,これを交換するという 操作をデータ列の左から右へ走査することを順次続 け,結果的に,右端から順にデータを確定させる. 背の順 に並ぶよ バブルソートの擬似コード for (i = n; i 2; i++){ for (j=1; j i-1; j++){ if (aj > aj+1) swap (aj, aj+1); } } バブルソートの例(1) (4,10,5,2,1,7,9,3,8,6) i j (4,10,5,2,1,7,9,3,8,6) i j (4,5,10,2,1,7,9,3,8,6) j i (4,5,2,10,1,7,9,3,8,6) j あとはよろしく i (4,5,2,1,7,9,3,8,6,10) i バブルソートの例(2) (4,5,2,1,7,9,3,8,6,10) i j (4,5,2,1,7,9,3,8,6,10) i j (4,2,5,1,7,9,3,8,6,10) i j あとはよろしく (4,2,1,5,7,3,8,6,9,10) i ...をつづける! バブルソートの計算量 n個のデータのソートに必要な最悪比較回数 for (i = n; i 2; i++){ for (j=1; j i-1; j++){ if (aj > aj+1) swap (aj, aj+1); } } O( ? ) ちょこっと工夫: j=1,…, i-1で入れ替えが一度もなければソート終了 挿入法(insertion sort) a1からai-1がすでにソートされていると仮定して,aiをしか るべき正しい位置に挿入する.すなわち,aiよりも大きいデ ータを右側にシフトした跡,その空き場所にaiを挿入する. 挿入法の擬似コード for(i = 2; i n; i++){ w:=ai; j:=i; while(aj-1>w and j>1){ aj:=aj-1; //移動 j:=j-1; } aj:=w; } //挿入 挿入法の例 (4,10,5,2,1,7,9,3,8,6) j-1 W=10 (4,10,5,2,1,7,9,3,8,6) j-1 W=5 (4,10,10,2,1,7,9,3,8,6) j-1 W=5 (4,5,10,2,1,7,9,3,8,6) j-1 W=5 (4,5,10,2,1,7,9,3,8,6) j-1 W=2 あとはよろしく 挿入法の計算量 n個のデータのソートに必要な最悪比較回数 for(i = 2; i n; i++){ w:=ai; j:=i; while(aj-1>w and j>1){ aj:=aj-1; //移動 j:=j-1; } aj:=w; } //挿入 O( ? ) 挿入法の計算量(続) for(i = 2; i n; i++){ w:=ai; j:=i; while(aj-1>w and j>1){ aj:=aj-1; //移動 j:=j-1; } aj:=w; } //挿入 ちょこっと工夫: リスト構造を用いれば,挿入場所を 移動をしなくてもよい.でも挿入場所 をみつけるのに,おなじだけwhileを まわす? 挿入法の計算量(続々) n個のデータのソートに必要な平均比較回数 場合 Whileの反復回数 ai<a1 i-1回 a1ai<a2 i-2回 ... 各場合が等確率に 起こるとすると, ... ai-2ai<ai-1 1回 ai-1ai 0回 i1 1 n i 1 1 i k 2 4 n(n 1) i 2 i 2 k 0 n Selection/Bubble/Insertionの比較 長所 選択法 バブル 挿入法 短所 ヒープソート(heap sort) 選択法で最小値をみつけるときに,ヒープを用い て効率よく行う. ヒープ: ◆ 最小値をO(1)でみつける. ◆ 最小値を削除してヒープ構造 を保つのに,O(log k)でできる. (kはヒープの中の要素数) ヒープ 根付き2分木:根をもつ(親子関係のある)木で各頂点の子が2 個以下. 完全2分木:頂点を左詰で並べた根付き2分木. •すべて葉は根からの深さが高々1 しか違わない. (深さmか,m-1に葉がある) •深さmの葉は左詰め. •深さがm-2以下の頂点は子をちょうど2つもつ. ヒープ: ◆ 完全2分木 ◆ 各頂点がデータを持つ ◆ 親頂点のデータは子頂点のデータよりも小さい d-ヒープ:子がd個以下の完全d分木からなるヒープ.単にヒープというと,2-ヒープを指す. ヒープかな? 図の上下が親子関係を表す 1 1 3 5 2 4 4 3 7 1 2 6 5 4 5 7 6 1 1 2 3 6 3 2 5 8 3 6 3 7 5 8 2 6 3 5 ヒープソートの擬擬似コード 1: {a1, …, an}をヒープ化; 2: for(i=1;in-1; i++){ 3: ヒープから最小値を取り出して,aiと入れ替え; 4: {ai+1, …, an}を再ヒープ化; 5: } •最小値はヒープの •1行目と3行目は... にあるので,3行目はO( )でできる. DeleteMin(1) 1.最小値を根からとる. 1 2 3 7 根のデー タがない! 5 8 6 DeleteMin(2) 2.とりあえず,最後のデータを移動 6 2 3 7 5 8 6 親子のデータ の大きさ関係 が崩れる DeleteMin(3) 3.ダウンヒープ ajで親子のデータの大小関係が崩れているとする. (1)ajの子のデータの小さい方をaiとする (2)aj<aiならば,ajとaiを入れ替える. (3)これを子がなくなるか,あるいはどの子よりもajが小 さくなるまで繰り返す. 6 2 2 3 7 5 8 2 6 3 7 5 8 3 6 7 なぜ,小さい子どもと入れ替えるの? 5 8 ヒープソートの操作 1: {a1, …, an}をヒープ化; 2: for(i=1;in-1; i++){ 3: ヒープから最小値をみつけてi番目に格納; 4: DeleteMin; 1 5: } 1行目は? //最小値をヒープから取り除く 6 2 5 2 5 3 7 8 6 3 7 8 2 6 5 3 7 8 2 3 5 6 7 8 ヒープの初期化 データ数nが既知 1. 1頂点からなる完全2分木をn個作り,データを割り振る. 2. 以下の走査を繰り返して1つのヒープにする 2つのヒープがあるときに,新しい1点wを根として, これらのヒープを部分木とするような完全2分木から 1つのヒープを作る.このとき,ダウンヒープの走査で ヒープの条件を満たすようにする. ヒープの初期化操作の例(1) (4,10,5,2,1,7,9,3,8,6)のヒープをつくる 1.とりあえず,データを入れる 4 5 10 2 3 1 8 6 7 9 ヒープの初期化操作の例(2) 10 2.ダウンヒープを繰り返す 2 4 ダウンヒープ 1 7 8 6 1 2 9 3 3 8 5 10 2 OK 3 1 8 6 OK 10 6 1 2 3 8 10 6 ヒープの初期化操作の例(3) 2.ダウンヒープを繰り返す ダウンヒープ 4 5 1 2 3 6 8 10 7 9 1 OK 3 4 5 2 6 8 10 7 9 ヒープソートの計算量 1: {a1, …, an}をヒープ化; O(ヒープの深さ) 2: for(i=1;in-1; i++){ 3: ヒープから最小値をみつけてi番目に格納; O(1) 4: DeleteMin; //最小値をヒープから取り除く O(ヒープの深さ) 5: } 1 6 2 5 2 5 3 7 8 6 3 7 8 2 6 5 3 7 8 k個のデータを格納するヒープの深さは? 2 3 5 6 7 8 ヒープの深さ k個のデータを格納するヒープの深さは? 深さ0 1 深さ1 5 2 3 4 6 8 7 9 10 深さ2 深さ3 深さiに格納で きるデータの 個数は? 深さdのヒープ全 体に格納できる データの個数 は? 2d+1-1 2d-1<k2d+1-1を満たす. よって, 2dk<2d+1. すなわち,d=|_ log k 」 ヒープソートの計算量(続) 1: {a1, …, an}をヒープ化; O(要素数 × ヒープの深さ) 2: for(i=1;in-1; i++){ 3: ヒープから最小値をみつけてi番目に格納; O(1) 4: DeleteMin; //最小値をヒープから取り除く O(log (n-i)) 5: } Totalで4行目: log(n-1)+log(n-2)+…+log(1)=log( (n-1)! ) n log n 1行目もO(n log n)は明らか.ちゃんと算定すると,O(n) ヒープソートの計算量:O( ) ヒープの初期化はO(n) ただし,データ数nは既知 (n=2d-1と仮定) ヒープの大きさ ヒープの数 ダウンヒープの回数 1 (葉に対応) 2d 0 3 2d-1 1 … … … n=2d -1 1 = 20 d Total: 2d-1+2・ 2d-2 +3・ 2d-3 +... +d・ 20= 2d+1-d-2 = O(n) ヒープソートの例 (4,10,5,2,1,7,9,3,8,6)のヒープをつくる 1 5 2 6 7 3 4 10 5 2 9 8 10 10 6 7 4 10 8 3 5 4 5 6 7 9 8 8 4 5 3 6 7 3 4 3 2 8 9 10 6 7 9 あとはよろしく 9 完全2分木の実現 ◆ 構造体:各頂点が親,子へのポインタを持つ. ◆ 配列:順番に格納 1 2 4 8 3 5 6 A= 1 2 3 7 A[i]の子はA[2i] とA[2i+1] 親は,A[└i/2」] 4 5 6 7 8
© Copyright 2024 ExpyDoc