ソートアルゴリズム
最后更新时间:
文章总字数:
预计阅读时间:
挿入ソート
擬似コード
1 |
|
以下は単調減少順のINSERTION-SORT
1 |
|
ループ不変式
初期条件:
ループ不変式がループの最初の繰返し(の繰返し)の直前で成立していることを示すことから始める。
このとき、部分配列は唯一の要素 から成され、実際、元 は格納されていた要素と等しいので、この部分配列はトリビアルにソート済みである。
よって、最初の繰返しの直前でループ不変式は真である。ループ内条件:
ループ不変式をすべての繰返しの直前で真であることを示すため、
1回の繰返しがループ不変式を維持することを確認する。
for ループの本体が行っているのは、を入れるべき場所が見つかるまで , をそれぞれ 1 つ右に移し(第 4〜7 行)、 空いた場所 に値を挿入する(第 8 行)。
この結果、部分配列は元 に格納されていた要素から構成されているが、すでにソートされている。
for ループの次の繰返しのためにの値を 1 増やす(incrementing)とループ不変式が維持される。 終了条件:
最後に、ループの停止を調べる。ループ変数は初期値が 2 で、各繰返しで 1 ずつ増加する。
第 1 行での値がを超えれば、ループは停止する。つまり、 で停止し、部分配列 は、開始時点で に格納されていた要素がすべて含まれている。
これらの要素はすでにソートされている。したがって、アルゴリズムは正当である。
解析
最悪の場合の定義 入力配列が降順に並んでいる場合、各要素を正しい位置に挿入するために、それ以前のすべての要素と比較する必要があります。このとき、最悪実行時間が生じます。
実行時間の解析 挿入ソートの実行時間
は、以下のループの各行のコストに基づいて計算されます。 外側の for ループ (2行目から8行目):
に対して実行されます。 内側の while ループ (5行目から7行目): 最悪の場合、while ループは
が配列 のすべての要素より小さい場合に実行され、比較と移動が 回行われます。
実行時間の式 各行のコストを
とした場合、最悪の場合の実行時間は次のように表されます。 和の計算 以下の和を計算します。
を計算: 式
を用いると: 実行時間の整理 これを
に代入すると: さらにまとめると:
線形関数としての表現 最悪の場合の実行時間は、以下のように表されます:
ここで:
以上が、挿入ソートの最悪実行時間を導く過程です。この計算により、挿入ソートは最悪の場合において
線形探索
擬似コード
以下は線形探索である
1 |
|
以下は2分探索である
反復:
1 |
|
再帰:
1 |
|
選択ソート
擬似コード
1 |
|
最悪実行時間は
マージソート
擬似コード
1 |
|
1 |
|
以下はセンチネルを使用せずのMERGE
1 |
|
解析
以下は、マージソート(Merge Sort)の最悪実行時間について、簡単に説明します。
マージソートの基本動作
分割(Divide)
配列を半分に分割し、各部分を再帰的にソートします。この操作は配列サイズがの場合、分割の深さが レベルになります。 統治(Conquer)
各部分配列を結合(マージ)してソート済みの配列を作成します。各レベルで配列全体にわたってマージ操作を行うので、各レベルのコストはです。
再帰的な式の構築 分割と結合を考慮すると、マージソートの実行時間
は以下のような再帰式で表されます: :配列を2つに分割し、それぞれの部分配列をソートする時間。 :現在のレベルでのマージ操作に必要な時間。
再帰式の解法
- 再帰式を展開すると、分割の深さごとにコストを計算できます。
- 再帰の深さは
レベルであり、各レベルのコストは です。 - すべてのレベルのコストを合計すると:
最悪実行時間の結論 最悪実行時間は再帰的分割と統治に基づき、次のように表されます:
バブルソート
擬似コード
1 |
|
ループ不変式
行2 ~ 4のforループ 行2-4の for ループの各繰り返しの開始時点で、部分配列
は、ループ開始前に に存在していた要素から構成されますが、その順序は変わっている可能性があります。 ただし、先頭の要素 はその部分配列内で最小の要素です。 初期条件:
初期状態では、部分配列は最後の要素のみを含んでおり、この要素は自明的に部分配列内の最小要素です。 ループ内条件:
各ステップでと を比較し、 をその部分配列内で最小の要素にします。ループの繰り返し後、部分配列の長さは1つ増加し、先頭の要素は依然としてその部分配列内で最小の要素です。 終了条件:
ループはのとき終了します。ループ不変式によると、 は 内で最小の要素であり、 はループ開始前の に存在していた要素から構成されています。
行1 ~ 4のforループ 行1-4の for ループの各繰り返しの開始時点で、部分配列
は、 内の 個の最小要素で構成され、昇順に整列されています。 一方、 は 内の残りの 個の要素で構成されています。 初期条件:
初期状態では、部分配列は空であり、自明的に部分配列内の最小要素が含まれています。 ループ内条件:
- の結果から、内側のループの実行後、
は部分配列 内で最小の要素になります。そして外側のループ開始時点では、 は の要素より小さい要素から構成され、昇順に整列されています。 したがって、外側のループの実行後、部分配列 は の要素より小さい要素から構成され、昇順に整列されます。
- 終了条件:
ループはのとき終了します。この時点で配列 はすべての要素を含み、昇順に整列されています。
ヒープソート
ヒープ条件の維持
擬似コード
1 |
|
MIN-HEAPIFYバージョン
1 |
|
再帰の代わりに繰り返し構造子 (ループ) を使うバージョン
1 |
|
解析
操作の流れ MAX-HEAPIFYは、与えられた節点
を根とする部分木が max ヒープ条件を満たすように調整する操作です。この操作の流れは以下の通りです: 比較と選択:
節点の値をその左右の子( および )の値と比較し、3つの中で最大の値を持つ節点を特定します。 交換と再帰呼び出し:
最大値を持つ節点がではない場合、節点 とその最大値を持つ子を交換します。その後、交換によって影響を受けた子部分木に対して再帰的に MAX-HEAPIFY を呼び出します。
実行時間の解析:
1回の呼び出しのコスト:
1回の比較操作(左右の子と比較)にかかる時間は定数時間です。ただし、交換後に再帰的に操作を繰り返すため、実行時間は部分木の高さに依存します。 再帰関係:
再帰的な呼び出しに基づく実行時間は以下の漸化式で表されます:ここで、 は、節点 の2つの子のうち、より大きな部分木のサイズを示します。 解法と結論:
マスター定理(画像の参照)を適用すると、この漸化式の解は:となります。したがって、MAX-HEAPIFY の最悪実行時間は木の高さ( )に比例します。
ヒープの構築
擬似コード
1 |
|
MAX-HEAP-INSERTを呼び出しバージョン
1 |
|
解析
ループ不変式
ループ不変式の定義:
for ループ(行2 - 3)の各繰り返しの開始時点で、各節点
初期条件:
ループの最初の繰り返しの直前では、である。
このとき、は葉ノードであり、葉ノードは自明的に max ヒープの根である。したがって、ループ不変式は成立する。 ループ内条件:
各繰り返しで、節点の左右の子を根とする部分木に対して MAX-HEAPIFY を呼び出す。この操作により、節点 を根とする部分木が max ヒープ条件を満たすようになる。
さらに、次の繰り返しではが 1 減少するため、ループ不変式は維持される。 終了条件:
手続きはで終了する。ループ不変式によれば、終了時点で各節点 が max ヒープの根である。したがって、配列全体が max ヒープになっている。
実行時間
MAX-HEAPIFY のコスト:
MAX-HEAPIFY の実行時間は節点の高さに比例し、最悪の場合です。 控える必要な事実:
- 高さ
の節点数はおおよそ 個です。 - n個節点を含むヒープの深さはおおよそ
である。
- 高さ
全体のコスト:
BUILD-MAX-HEAP のコストは、すべての節点に対して MAX-HEAPIFY を適用する際の時間の合計です。この合計は以下のように表されます:公式 を用いると:
漸近的評価:
付録の公式(図中の式)を用いると、この和は定数に収束することが示されます。したがって:
ヒープソートアルゴリズム
擬似コード
1 |
|
解析
ループ不変式
初期条件:
部分配列は空であるため、この時点でループ不変式は成立している。 維持条件:
は部分配列 の中で最大の要素であり、 の要素よりも小さい。
この要素を位置に移動させることで、部分配列 は最大の要素を含み、整列されている。
ヒープのサイズを減らし、MAX-HEAPIFY を呼び出すことで、部分配列が再び max ヒープになる。
その後、をデクリメントすることで、次の繰り返しに対するループ不変式が整備される。 終了条件:
ループが終了するとき、である。
この時点で、部分配列は整列済みであり、 は配列内で最小の要素である。
したがって、配列全体は整列されている。
実行時間
BUILD-MAX-HEAPの呼出しに
クイックソート
擬似コード
1 |
|
1 |
|
以下はHOAREの最初のPARTITIONアルゴリズム
1 |
|
乱択版擬似コード
1 |
|
1 |
|
解析
ループ不変式
行 3 - 4 の各繰り返しの開始時点で、部分配列
初期条件 ループの最初の繰り返しの直前では、
かつ である。このとき、部分配列 と は空であるため、ループ不変式が成立する。 維持条件 各繰り返しで、次の 2 つの場合を考える:
の場合:
この場合、を単に 増加させる。これにより、 は に加えられることなく より大きい部分に残り、ループ不変式が維持される。 の場合:
この場合、を 増加させた後、 と を交換する。この操作により、 は に追加され、 以下の値として正しい位置に収まる。結果としてループ不変式が維持される。
終了条件 ループは
で停止する。この時点で、 は空となり、配列全体は次の 3 つの部分に分割されている: : 以下の値。 : より大きい値。 :ピボット値 。
ピボット値を正しい位置
最悪実行時間
漸化式 QUICKSORT の最悪実行時間は、分割が極端に偏った場合(片側にすべての要素が集中するケース)に発生します。この場合、漸化式は次のように表されます:
ここで、 は部分配列の要素数を示します。 最悪ケース 最悪ケースでは、分割が片側に極端に偏るため、
または となります。この場合の漸化式は: 漸化式の解 上記の漸化式を展開すると:
最後の和は等差数列であるため:
期待実行時間
分割の期待ケース RANDOMIZED-QUICKSORT は、ランダムにピボットを選択することで、分割がほぼ均等になるように設計されています。このアルゴリズムの期待実行時間を解析するには、次の漸化式を考えます:
ただし、ランダム性を考慮すると、分割が偏りにくいため、 に近いケースが期待されます。 比較回数の期待値
- 補題: 任意の2つの要素
と (i < j) が与えられたとき、この2つの要素が比較される確率は である。 証明: - 比較回数
をランダム変数として、指標確率変数を と定義する。 - 以上より、
になっている。 - 期待値
は次のように評価されます: 補題を用いると: 変数を に変換し、調和数の公式 を用いると:
- 補題: 任意の2つの要素
結論 ランダム性によって分割のバランスが期待されるため、RANDOMIZED-QUICKSORT の期待実行時間は次のように評価されます:
計数ソート
擬似コード
1 |
|
1 |
|
解析
実行時間
計数ソートの実行時間を検討する。 第2 ~ 3行のforループに
基数ソート
擬似コード
1 |
|
解析
補題 8.3
証明
Radix-Sort
の正当性はソートされている列に関する帰納法によって示すことができる(練習問題
8.3-3 を参照)。
実行時間の解析は中間ソートとして用いる安定ソートに依存する。
各桁のうち 0 から
この操作を
となる。
補題 8.4
証明
値を各桁に対して、各キーを
各桁あたりの取りうる値の数を
とする。 サブルーチン Counting-Sort の実行時間は
であり、これは各桁ごとのコストを決定する。 全体の桁数
に基づき、Radix-Sort の実行時間は: 条件
を満たすとき、実行時間は に近くなる。
したがって、総実行時間は次の式で表される:
バケツソート
擬似コード
1 |
|
解析
実行時間
- 実行時間の分解
バケットソートの実行時間を解析するため、以下の2つの部分に分けて考える:
- 第7行以外の実行時間は、最悪の場合でも
時間である。 - 第7行の挿入ソートにかかる実行時間は、各バケット内の要素数
に依存する。
- 第7行以外の実行時間は、最悪の場合でも
- 全体の実行時間 挿入ソートは 2
次の多項式時間で動作するため、バケットソート全体の実行時間
は以下の式で表される:
平均時の実行時間の期待値
期待値の計算
期待値を計算する際、入力分布の一様性に基づき、期待値の線形性を適用する:
各バケットの要素数
の期待値 各バケットに要素が均等に割り振られると仮定すると:
結論
バケットソートの期待実行時間は以下のように評価される:
線形期待時間選択アルゴリズム
擬似コード
1 |
|
以下は反復バージョン
1 |
|
1 |
|
1 |
|
解析
定理 9.2
証明
分割が有用である確率の定義 有用な分割とは、分割が進むたびに要素の集合が十分に減少する分割を指す。各分割について次のように定義する:
- 集合のサイズ:
(世代 における集合)。 - 次の分割後の集合サイズ:
。
ここで:
を定義する。つまり、 は世代 における分割後の集合の個数を表す。 - 集合のサイズ:
分割の有効性と確率
- 分割が有用である確率は少なくとも 1/2 である。
- このとき、分割のたびに集合のサイズは
以下に縮小する( は元の入力配列サイズ)。
期待値の計算 分割が有効である場合に、比較回数の期待値を計算する:
ここで
であることから:
結論
等比数列の和を用いて整理すると:
したがって、RANDOMIZED-SELECT の期待実行時間は次のように評価される:
線形最悪時間選択アルゴリズム
擬似コード
1 |
|
以下は3グループのバージョン
1 |
|
解析
定理 9.3
長さ
証明
概要 手続き SELECT を用いて、長さ
の入力配列 に対して i 番目に小さい要素を求める場合を考える。
このアルゴリズムの実行時間は以下の漸化式で表される:漸化式の展開
- 第 16、23、および 24 行における再帰呼び出しの外側でかかる時間の上界を求める。
- 第 1-10 行の while ループ は最大
時間で終了する。第 12-13 行で行われる 5 要素グループのソートは、グループ数 に基づき 時間かかる。
部分問題の削減 ピボット選択後、再帰的な SELECT 呼び出しでは、次のように入力サイズが縮小される:
- ピボットの両端から除外される要素数の合計は
以上である。
これをもとに、漸化式
を用いて解析を進める。 - ピボットの両端から除外される要素数の合計は
漸化式の解 漸化式を次のように展開する:
結論
以上の解析より、SELECT の実行時間は
この結果は SELECT が線形時間で動作することを示している。