コンピュータ基礎演習 ー高速ソートー 岩井 儀雄 [email protected] 高速なソートアルゴリズム 整列アルゴリズムの処理速度 単純なアルゴリズム 比較回数と交換回数の大小 安定,プログラム容易,作業領域不要 バブル,選択,挿入ソート: O(n2) 高速なアルゴリズム 不安定,プログラム複雑,作業領域要 シェルソート:平均O(n1.25~n1.5) クイックソート:平均O(nlogn)~最悪O(n2) マージソート: O(nlogn) (安定) シェルソート(Shell sort) N 個のデータを整列 H←N/2, I←N/H H組のI個のデータを挿入ソートする H←H/2, I←N/H で H が 0 になるまで繰り返し シェルソート 74 22 64 91 3 87 6 55 13 19 28 30 45 82 46 66 74 22 64 91 3 87 6 55 13 19 28 30 45 82 46 66 同一色内で挿入ソートを実行する 同一色内ではソートが完了していることに注目 シェルソート 74 22 64 91 3 87 6 55 13 19 28 30 45 82 46 66 13 19 28 30 3 82 6 55 74 22 64 91 45 87 46 66 同一色内で挿入ソートを実行する 同一色内ではソートが完了していることに注目 シェルソート 74 22 64 91 3 87 6 55 13 19 28 30 45 82 46 66 13 19 28 30 3 82 6 55 74 22 64 91 45 87 46 66 13 19 28 30 3 82 6 55 74 22 64 91 45 87 46 66 同一色内で挿入ソートを実行する 同一色内ではソートが完了していることに注目 シェルソート 74 22 64 91 3 87 6 55 13 19 28 30 45 82 46 66 13 19 28 30 3 82 6 55 74 22 64 91 45 87 46 66 3 19 6 30 13 22 28 55 45 82 46 66 74 87 64 91 同一色内で挿入ソートを実行する 同一色内ではソートが完了していることに注目 シェルソート 74 22 64 91 3 87 6 55 13 19 28 30 45 82 46 66 13 19 28 30 3 82 6 55 74 22 64 91 45 87 46 66 3 19 6 30 13 22 28 55 45 82 46 66 74 87 64 91 3 19 6 30 13 22 28 55 45 82 46 66 74 87 64 91 同一色内で挿入ソートを実行する 同一色内ではソートが完了していることに注目 シェルソート 74 22 64 91 3 87 6 55 13 19 28 30 45 82 46 66 13 19 28 30 3 82 6 55 74 22 64 91 45 87 46 66 3 19 6 30 13 22 28 55 45 82 46 66 74 87 64 91 3 19 6 22 13 30 28 55 45 66 46 82 64 87 74 91 同一色内で挿入ソートを実行する 同一色内ではソートが完了していることに注目 シェルソート 74 22 64 91 3 87 6 55 13 19 28 30 45 82 46 66 13 19 28 30 3 82 6 55 74 22 64 91 45 87 46 66 3 19 6 30 13 22 28 55 45 82 46 66 74 87 64 91 3 19 6 22 13 30 28 55 45 66 46 82 64 87 74 91 3 19 6 22 13 30 28 55 45 66 46 82 64 87 74 91 同一色内で挿入ソートを実行する 同一色内ではソートが完了していることに注目 シェルソート 74 22 64 91 3 87 6 55 13 19 28 30 45 82 46 66 13 19 28 30 3 82 6 55 74 22 64 91 45 87 46 66 3 19 6 30 13 22 28 55 45 82 46 66 74 87 64 91 3 19 6 22 13 30 28 55 45 66 46 82 64 87 74 91 3 6 13 19 22 28 30 45 46 55 64 66 74 82 87 91 同一色内で挿入ソートを実行する 同一色内ではソートが完了していることに注目 シェルソートの実装(C言 語) int greaterthan(DATATYPE a, DATATYPE b); /* 順序を定義する関数 */ void swap(DATATYPE *a, DATATYPE *b); /* 値を交換する関数 */ void shellsort( DATATYPE *A, size_t n) { int i,j,inc; inc = n/2; while (inc > 0) { for (i = inc; i<n; ++n) { j = i-inc; while (j > 0) /* 挿入ソートを実行する */ if (greaterthan(A[j],A[j+inc])) { /* 値交換,前方に進む */ swap( &A[j], &A[j+inc] ); j -= inc; } else j = 0; /* ソート済みなのでwhile ループを抜ける */ } inc /= 2; } } /* 要チェック(動作未確認) */ マージソート (merge sort) 外部記憶装置向けのソート 各要素をシーケンシャルにアクセスする 二つのソートされた列から一つのソートされた 列を作る(併合,merge) マージソート(merge sort) 整列済 新しいソート済み列 A列 3 13 46 55 B列 30 45 74 87 先頭を大小比較し 小さなほうを取り出す マージソート(merge sort) 整列済 新しいソート済み列 3 A列 B列 30 13 46 55 45 74 87 先頭を大小比較し 小さなほうを取り出す マージソート(merge sort) 整列済 新しいソート済み列 3 13 A列 B列 30 45 46 55 74 87 先頭を大小比較し 小さなほうを取り出す マージソート(merge sort) 整列済 新しいソート済み列 3 13 30 A列 B列 45 46 55 74 87 先頭を大小比較し 小さなほうを取り出す マージソート(merge sort) 整列済 新しいソート済み列 3 13 30 45 A列 46 55 B列 74 87 先頭を大小比較し 小さなほうを取り出す マージソート(merge sort) 整列済 新しいソート済み列 3 13 30 45 46 55 A列 B列 74 87 先頭を大小比較し 小さなほうを取り出す マージソート(merge sort) 整列済 新しいソート済み列 3 13 30 45 46 55 A列 B列 74 87 先頭を大小比較し 小さなほうを取り出す マージソート(merge sort) 整列済 新しいソート済み列 3 13 30 45 46 55 74 87 A列 B列 どちらかの列が空になったら 残りの列のデータをその順序で コピーする マージソート(merge sort) データ列を真ん中で2つの部分列a,bに 分割する(データが一つしかなければ 整列済みなので戻る) 部分列a,bをそれぞれ整列を行う 整列済みの部分列a,bをマージする マージソートの実装(C言 語) #include <string.h> int lessthan(DATATYPE a, DATATYPE b); /* 順序を定義する関数 a<b */ void copy(DATATYPE *a, DATATYPE *b); /* 値を代入する関数 a←b */ void mergesort(DATATYPE *A, int low, int high, DATATYPE *B) { /* Bは作業領域 */ int m,i,j,k; for (i=low; i<=high; ++i) copy(&B[i],&A[i]); /* データをコピー */ if (low >= high) return; /* 要素が一つの場合は戻る */ m = (low+high)/2; /* 列を2つに分割する位置を決める */ mergesort( B, low, m, A ); /* 前半部分のソート */ mergesort( B, m+1, high, A ); /* 後半部分のソート */ j = low; k = m+1; i=low; while (j <= m && k <= high) if (lessthan(A[j],A[k])) copy( &B[i++], &A[j++] ); else copy( &B[i++], &A[k++] ); while (j <= m) copy( &B[i++], &A[j++] ); while (k <= high) copy( &B[i++], &A[k++] ); } マージソートの実行イメージ 整列前A low=0 55 時間 55 55 13 13 3 3 分割 13 13 3 55 13 13 87 46 3 3 分割 45 45 3 併合 45 30 high=7 74 55 45 74 分割 87 87 74 30 併合 45 87 46 87 併合 46 46 30 30 併合 分割 30 46 55 分割 30 30 併合 74 46 13 併合 分割 74 3 併合 分割 45 45 55 46 74 87 74 87 マージソートの性質 安定な整列 時間計算量 空間作業量 常に O(nlogn) 整列する配列と同じ作業領域が必要 O(n) もともと外部記憶装置用のソートアルゴリズムの ため クイックソート(quick sort) 高速なソートアルゴリズム 安定な整列ではない C言語でもライブラリで用意されている void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); クイックソート(quick sort) データ列から枢軸(ピボット, Pivot)を選 ぶ 枢軸の値より,小さいもの,大きいも のに分割する 分割されたそれぞれを整列する. クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 Pivot 66 クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 Pivot 66 45 13 30 64 55 91 クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 Pivot 66 45 13 30 64 55 19 74 91 クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 Pivot 66 45 13 30 64 55 19 46 87 74 91 クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 Pivot 66 45 13 30 64 55 19 46 22 28 87 74 91 赤い矢印のところのデータとピボットを交換 赤い矢印がピボットを差し, 赤い矢印から左がピボットより小さい→再帰的に quick sort 赤い矢印から右がピボットより大きい→再帰的に quick sort クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 Pivot 66 45 13 30 64 55 19 46 22 28 66 74 91 87 赤い矢印のところのデータとピボットを交換 赤い矢印がピボットを差し, 赤い矢印から左がピボットより小さい→再帰的に quick sort 赤い矢印から右がピボットより大きい→再帰的に quick sort クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 Pivot 66 45 13 30 64 55 19 46 22 28 66 74 91 87 Pivot Pivot 28 87 クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 Pivot 66 45 13 30 64 55 19 46 22 28 66 74 91 87 Pivot Pivot 28 22 13 46 45 87 74 91 クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 Pivot 66 45 13 30 64 55 19 46 22 28 66 74 91 87 Pivot Pivot 28 22 13 19 64 55 30 46 45 87 74 91 クイックソート(quick sort) 45 13 30 64 55 74 87 22 28 46 19 91 66 Pivot 66 45 13 30 64 55 19 46 22 28 66 74 91 87 Pivot Pivot 28 22 13 19 28 55 30 46 45 64 87 74 87 91 クイックソート(quick sort) 45 13 30 64 55 19 46 22 28 66 74 91 87 Pivot Pivot 28 22 13 19 28 55 30 46 45 64 Pivot 19 87 74 Pivot 64 87 Pivot 要素数1 なので終了 91 Pivot 要素数1 なので終了 クイックソート(quick sort) 45 13 30 64 55 19 46 22 28 66 74 91 87 Pivot Pivot 28 22 13 19 28 55 30 46 45 64 Pivot 22 64 28 74 Pivot 19 13 87 55 30 46 45 87 Pivot 要素数1 なので終了 91 Pivot 要素数1 なので終了 クイックソート(quick sort) 45 13 30 64 55 19 46 22 28 66 74 91 87 Pivot Pivot 28 22 13 19 28 55 30 46 45 64 Pivot 19 22 64 28 74 Pivot 19 13 87 55 30 46 45 64 87 Pivot 要素数1 なので終了 91 Pivot 要素数1 なので終了 クイックソート(quick sort) 22 13 19 28 55 30 46 45 64 Pivot Pivot 19 13 19 Pivot 要素数1 なので終了 22 64 28 Pivot 要素数1 なので終了 74 55 30 46 45 64 Pivot 45 87 Pivot 要素数1 なので終了 91 Pivot 要素数1 なので終了 クイックソート(quick sort) 22 13 19 28 55 30 46 45 64 Pivot Pivot 19 13 19 Pivot 要素数1 なので終了 22 64 28 55 30 46 45 64 Pivot Pivot 要素数1 なので終了 28 74 45 46 87 Pivot 要素数1 なので終了 91 Pivot 要素数1 なので終了 クイックソート(quick sort) 22 13 19 28 55 30 46 45 64 Pivot Pivot 19 13 19 Pivot 要素数1 なので終了 22 64 28 55 30 46 45 64 Pivot Pivot 要素数1 なので終了 28 74 45 30 55 46 87 Pivot 要素数1 なので終了 91 Pivot 要素数1 なので終了 クイックソート(quick sort) 22 13 19 28 55 30 46 45 64 Pivot Pivot 19 13 19 Pivot 要素数1 なので終了 22 64 28 55 30 46 45 64 Pivot Pivot 要素数1 なので終了 28 74 45 30 45 46 55 87 Pivot 要素数1 なので終了 91 Pivot 要素数1 なので終了 クイックソート(quick sort) 13 19 Pivot 要素数1 なので終了 22 28 55 30 46 64 Pivot Pivot 要素数1 なので終了 28 45 45 30 45 46 55 Pivot 30 Pivot 55 クイックソート(quick sort) 13 19 Pivot 要素数1 なので終了 22 28 55 30 46 45 30 45 46 55 Pivot Pivot 30 28 64 Pivot Pivot 要素数1 なので終了 28 45 55 46 クイックソート(quick sort) 13 19 Pivot 要素数1 なので終了 22 28 55 30 46 45 30 45 46 55 Pivot Pivot 30 28 64 Pivot Pivot 要素数1 なので終了 28 45 30 55 46 55 クイックソート(quick sort) 28 30 45 46 55 Pivot Pivot 30 28 30 Pivot 要素数1 なので終了 55 46 55 Pivot 要素数1 なので終了 クイックソート(quick sort) 28 30 45 46 55 Pivot Pivot 30 13 19 22 28 30 Pivot 要素数1 なので終了 55 45 46 55 Pivot 要素数1 なので終了 64 66 74 87 91 クイックソートの実装 (C言語) #include <stdio.h> int lessthan(DATATYPE a,DATATYPE b); /* 大小比較を行う関数 */ void copy(DATATYPE *a,DATATYPE *b); /* 値のコピーを行う関数 */ void swap(DATATYPE *a,DATATYPE *b); /* 値の交換を行う関数 */ int partition(DATATYPE *A,int l,int r) { int i,j,t; DATATYPE pivot; i = l-1; j = r; copy( &pivot, &A[r]); /* 右端をピボットとする */ for (;;) { while (lessthan(A[++i],pivot)) ; /* 左側を進める(pivotより小さい) */ while (i < --j && lessthan(pivot,A[j])) ; /* 右側を進める(pivotより大きい)*/ if (i >= j) break; /* 両側からぶつかったらループを抜ける */ swap(&A[i],&A[j]); /* 値を交換する */ } swap( &A[r], &A[i] ); /* pivot と交換する */ return i; } void quicksort(DATATYPE *A,int l,int r) { int v; if (l >= r) return; v = partition( A, l, r ); /* v の位置を pivot として,データを左右に振り分け */ quicksort( A, l, v-1 ); /* 左部分列をソート */ quicksort( A, v+1, r ); /* 右部分列をソート */ } クイックソートの性質 時間計算量 平均的に O(nlogn) 最悪 O(n2) (ピボットが端に来る場合) コンピュータ基礎演習 ーハッシュ法ー 岩井 儀雄 [email protected] ハッシュ法 (hashing) Hash: 切り刻む,細かに切るの意味 ハッシュ法とは,キーに一定時間の演 算Hを施して,データ格納のアドレスに 変換し,そのアドレスからデータを参 照するというキー・アドレス変換の技 法 目的のデータの探索時間が短縮可能 ハッシュ法 ハッシュ関数 ハッシュ値 キーの値xをデータのアドレス(通常は, 配列の添え字)へ変換する関数H ハッシュ関数が返す値 ハッシュテーブル データを格納する配列T ハッシュ法 キーXを持つデータは,配列Tの要素 T[H(X)] に格納される. ハッシュ関数の例 簡単なハッシュ関数の例) int hash(char *s) { int i= 0; while (*s) i += *s++; return i%100; } 実行例 文字列 one two three four five six seven eight nine ten ハッシュ値 22 46 36 44 26 40 45 29 26 27 文字列中の全ての文字コードを加算 その結果の100で割った余りをハッシュ値とする ハッシュ関数 実行例 文字列 one two three four five six seven eight nine ten ハッシュ値 22 46 36 44 26 40 45 29 26 27 欠点 異なる入力に対して同じハッ シュ値を返すことがある(衝 突) 衝突に対する対処法 チェイン法(chaining) 同じハッシュ値を持つデータをリス トでつなぐ方法 オープンアドレス法(open addressing) 別のハッシュ関数を使って再度ハッ シュする方法 チェイン法 ハッシュ表には連結リストへのポイン タをいれ,データはポインタでつなぐ ハッシュ表 [0] AAA A [1] [2] C … DD DDDD [N] NNN N AAAA 探索方法 ハッシュ値の計算 リストを線形探索 ハッシュ表 [0] AAA A [1] [2] C … DD DDDD [N] NNN N AAAA 探索方法 ハッシュ値の計算 AAAA の探索 ハッシュ表 H(AAAA) [0] AAA A [1] [2] C … DD DDDD [N] NNN N AAAA 探索方法 ハッシュ値の計算 リストを線形探索 AAAA の探索 ハッシュ表 H(AAAA) [0] AAA A [1] [2] C … DD DDDD [N] NNN N AAAA 探索方法 ハッシュ値の計算 リストを線形探索 AAAA の探索 ハッシュ表 H(AAAA) [0] AAA A [1] [2] C … DD DDDD [N] NNN N AAAA 探索方法 ハッシュ値の計算 リストを線形探索 AAAA の探索 ハッシュ表 H(AAAA) [0] AAA A [1] [2] C … DD DDDD [N] NNN N AAAA データの追加・削除 連結リストにおける挿入削除と同じ処理 ハッシュ値を計算して追加・削除する連結リ ストを決定する その連結リストに対して,追加・削除を行う. チェイン法の性質 探索の時間計算量 ハッシュ値の計算 O(1) 連結リストにおける線形探索 O(L) リストの平均長L = N/ハッシュ表の大きさB N << B N / B < 1 N BN /B 1 N >> B N / B N ハッシュ表がデータに比べて十分大きい場合→O(1) ハッシュ表がデータに比べて大きくない場合→O(N) チェイン法の性質 挿入の時間計算量 連結リストの先頭へのデータ挿入O(1) キーの重複チェック O(L) 削除の時間計算量 連結リストからのデータ削除 O(1) データの探索 O(L) チェイン法の性質 良好な性能を維持するためには 連結リストが長くならないように十分大き なハッシュ表を用意する できるだけ均等に分布するハッシュ関数H を用意する. オープンアドレス法 衝突が発生したときに,ある手順に 従って別の位置にデータを格納する (再ハッシュ) 再ハッシュの方法 例)k回目の再ハッシュ H(x,k) = (H(x) + k) mod B X A B C D E H(X) → 1 → 5 → 8 → 5 → 6 [0] [1] [2] [3] [4] [5] [6] [7] [8] 再ハッシュの方法 例)k回目の再ハッシュ H(x,k) = (H(x) + k) mod B X A B C D E H(X) → 1 → 5 → 8 → 5 → 6 [0] [1] [2] [3] [4] [5] [6] [7] [8] A 再ハッシュの方法 例)k回目の再ハッシュ H(x,k) = (H(x) + k) mod B X A B C D E H(X) → 1 → 5 → 8 → 5 → 6 [0] [1] A [2] [3] [4] [5] [6] [7] [8] B 再ハッシュの方法 例)k回目の再ハッシュ H(x,k) = (H(x) + k) mod B X A B C D E H(X) → 1 → 5 → 8 → 5 → 6 [0] [1] A [2] [3] [4] [5] B [6] [7] [8] C 再ハッシュの方法 例)k回目の再ハッシュ H(x,k) = (H(x) + k) mod B X A B C D E H(X) → 1 → 5 → 8 → 5 → 6 [0] [1] A [2] [3] [4] [5] B [6] [7] [8] C D: 衝突 再ハッシュH(x,1)=6 再ハッシュの方法 例)k回目の再ハッシュ H(x,k) = (H(x) + k) mod B X A B C D E H(X) → 1 → 5 → 8 → 5 → 6 [0] [1] A [2] [3] [4] [5] B [6] D [7] [8] C 再ハッシュの方法 例)k回目の再ハッシュ H(x,k) = (H(x) + k) mod B X A B C D E H(X) → 1 → 5 → 8 → 5 → 6 [0] [1] A [2] [3] [4] [5] B [6] D [7] [8] C E: 衝突 再ハッシュH(x,1)=7 再ハッシュの方法 例)k回目の再ハッシュ H(x,k) = (H(x) + k) mod B X A B C D E H(X) → 1 → 5 → 8 → 5 → 6 [0] [1] A [2] [3] [4] [5] B [6] D [7] E [8] C コンピュータ基礎演習 ー平衡木,AVL木ー 岩井 儀雄 [email protected] 平衡木 (Balanced Tree) 木の高さが,高々log N程度の2分探索木 二分探索木において平均的にO(log N)の性能を出すことができる. AVL木: (Adel’son -Vel’skii Landis) 2分探索木でかつ,全ての節において左部分木TLと右部分木TRの高さの差 H(TL)-H(TR)が1以内に収まらなければならない c 右部分木 左部分木 a d 高々1 b x H(TL(x)) – H(TR(x)) 1 AVL木 以下の制約によりN個の節を持つAVL木の高 さはO(log N) 探索を常にO(log N)で実行可能 c 右部分木 左部分木 a d 高々1 b x H(TL(x)) – H(TR(x)) 1 AVL木の要素探索 通常の2分探索木と同様に実行できる AVL木への要素の削除と挿入 挿入削除も基本的には2分探索木と同様 木のバランスが壊れたときに修正する処理 c 右部分木 左部分木 a d 高々1 b x H(TL(x)) – H(TR(x)) 1 AVL木への挿入 要素を新しい位置に挿入するのは2分 探索木と同様 その結果,部分木によっては高さが1 増加するので,挿入位置から根に向 かって高さの調整作業を行う AVL木の挿入(2) 修正の手順において,左の子vから親uへ上ってき たとする(右の子の場合も対称的に扱う) vを根とする部分木の高さが1増えた状態(そうで なければ修正の必要なし) 節点xに関して,その左部分木TL(x)とTR(x)に関する 状態 S(x)を以下のように定める S(x) = L E R H(TL(x)) > TR(x)) H(TL(x)) = TR(x)) H(TL(x)) < TR(x)) AVL木の挿入(3) 挿入前のS(u)→挿入後のS(u) S(u)=R → S(u)=E S(u)=E → S(u)=L 修正終了 uの親に移動して修正実行,根なら終了 S(u)=L → S(u)=L uはAVL木の条件を満たさなくなるので修正が 必要(回転処理を行う) AVL木の回転処理(1) S(v)=Lの場合 u S(v)=L S(v)=Lなので 左の木の方が 1高い v β α S(u)=L γ AVL木の回転処理(2) S(v)=Lの場合 S(v)=E v u α β γ AVL木の回転処理(3) S(v)=Rの場合 S(v)=R u v w S(w)=L or R α δ β γ AVL木の回転処理(4) S(v)=Rの場合 w u v α β γ δ 挿入実行例 L 2 を挿入 13 L 8 E 6 10 E E 4 14 7 E R 15 E 挿入実行例(2の挿入) L 13 L u 8 L v 6 10 E L 4 E 2 14 7 E R 15 E 挿入実行例(回転処理) 13 v 6 4 2 14 u 8 7 15 10 AVL木の要素削除 要素の除去は2分探索木と同様に行う その結果,高さの減少する部分木が存在すれば, その部分木の根から上へ修正作業を加える 挿入の場合と同様に,左の子vからその親uへ上っ てきたとする(右の子も対称的に扱える) vを根とする部分木の高さが1減った状態にある AVL木の要素削除(2) 挿入前のS(u) S(u)=L → S(u)=E S(u)=E → S(u)=R 左部分木の高さが1減ったためS(u)=E. uの高さが1減少し,修正はuの親へと続ける.ただし, uが根ならば終了する 修正終了 S(u)=R → S(u)=R uはAVL木の条件を満たさなくなるので,修正が必要 (回転処理を行う) AVL木の回転処理(1) S(w)=Eの場合 u S(u)=R w v α β 高さの差2 γ S(w)=E δ AVL木の回転処理(2) S(w)=Eの場合 w S(u)=R S(w)=L u v α β γ δ AVL木の回転処理(3) S(w)=Rの場合 u S(u)=R w v α β 高さの差2 γ S(w)=R δ AVL木の回転処理(4) S(w)=Rの場合 w S(u)=E S(w)=E u v α β γ δ AVL木の回転処理(5) S(w)=Lの場合 u S(u)=R w v S(w)=L z α β 高さの差2 ε γ δ AVL木の回転処理(6) S(w)=Lの場合 z S(u)=E or L S(z)=E w S(w)=E or R u v α β γ δ ε AVL木の計算量 N個の節点を持つAVL木の高さはO(log N) であるから,探索,挿入,要素削除(回 転処理を含む)は最悪時間計算量O(log N)で可能 他の平衡木 木の高さをO(log N)に抑えると,操作あ たりの計算量はO(log N)に抑えることが できる 他の平衡木として B木,B+木,2-3木などが用いられる B木 (B-tree) B木の条件 根は,葉であるか,あるいは2~m個の子を 持つ 内部の節はm/2~m個の子を持つ 根から全ての葉までの経路の長さが等しい 2-3木は m=1 のB木 補助記憶装置(ハードディスク等)に 適したデータ構造 B木 子へのポインタと キーの並び(整列済) m=5のB木の例 12 4 2 7 4 18 7 12 21 18 30 21 30 葉にはキーで引き出されるデータが付随するが省略 B木の探索 根から順次,内部節をたどって探索する. k1 x < k1 k2 k3 k4 k 2 x < k 3 k 4 x k 1 x < k 2 k 3 x < k 4 内部節では,キーが整列されているので, 2分探索を用いて子へのポインタを決定す る 以降,葉に到達するまで繰り返し B木への挿入 根から順次,内部節をたどって挿入位置を 探索する 挿入すべき位置に,要素を入れる余裕があ れば,挿入する そうでなければ,節を2つに分割して,そ のどちらかの正しい位置に挿入.親の節は, 子が増えるので順次挿入を繰り返す B木への挿入例 25 を挿入 12 4 2 7 4 18 7 12 21 18 30 21 30 B木への挿入例 25 を挿入 12 4 2 7 4 18 7 12 21 18 25 21 30 25 30 B木への挿入例 15 を挿入 12 4 2 7 4 18 7 12 21 18 25 21 30 25 30 B木への挿入例 15 を挿入 子が一杯なので 2つに分割する 12 4 2 7 4 18 7 12 21 18 25 21 30 25 30 B木への挿入例 15 を挿入 12 4 2 21 7 4 25 7 21 15 12 18 15 18 30 25 30 B木の削除 削除対象の要素位置を探索 削除したとき,節にm/2個以上残っていれば そのまま終了 m/2以下の時 隣の節の子の数がm/2+1個以上であれば,その節 と子を半分ずつにする そうでなければ,隣の節と併合する.併合すると, 親にとっては子が減るので,同様の処理を親に向 かって続ける B木の削除例 18を削除 12 4 2 7 4 18 7 12 21 18 30 21 30 B木の削除例 12 4 2 7 4 21 7 12 30 21 30 B木の削除例 4を削除 12 7 2 21 7 12 30 21 30 B木の削除例 4を削除 12 7 2 21 7 12 併合 30 21 30 B木の削除例 4を削除 12 7 2 12 7 21 12 30 21 30 B木の削除例 7 2 4を削除 12 7 21 12 30 21 30
© Copyright 2024 ExpyDoc