# Algorithms
# Sort
# Quick Sort
https://www.youtube.com/watch?v=Hoixgm4-P4M (opens new window)
ランダムなデータの並び替えに使われる、インメモリでのソート方法。
- pivot は、各ループが回り終わったあとに、ソート完了後の正しい位置にいる
- pivot の左側は pivot より小さく、右側は大きい
JavaScriptは末尾再帰最適化に対応していない。このため、再帰処理を使うとstack overflowになりがち。下記のようにwhileで実装するのが安心。
function quicksort(array) {
// タスクを積んでいくスタック
// [{minPos, maxPos}, .....]
let task = [];
task.push({ minPos: 0, maxPos: array.length - 1 });
while (task.length) {
const { minPos, maxPos } = task.pop();
// Base Case これ以上の処理が必要ない場合は終了する
if (minPos >= maxPos) continue;
// 最後の要素をpivotにする
let pivot = array[maxPos];
// クイックソートでは、pivotよりも小さい値を左側から詰めていく。
// そのために、詰めるポジションを保持しておく変数。
let leftWall = minPos;
for (i = minPos; i < maxPos; i++) {
if (array[i] <= pivot) {
// pivotより小さい数字を見つけたら左から詰めていく
swap(array, leftWall, i);
// 数字を詰めたら、次回に詰めるポジションを一つずらしておく
leftWall += 1;
}
}
// 最後に、pivotとleftWallを入れ替えれば一巡が完了する
// この時点で、このpivotは正しい位置にいる(左側は小さく、右側は大きい)
swap(array, leftWall, maxPos);
// leftWall = pivotのポジション
task.push({ minPos, maxPos: leftWall - 1 });
task.push({ minPos: leftWall + 1, maxPos });
}
}
quicksort([3, 6, 2, 4, 1, 5]); // => [1,2,3,4,5,6]
# Minimum Heap Tree
https://www.youtube.com/watch?v=NCuaebwQLKU (opens new window)
親が子より必ず小さくなるツリー。
- 要素の追加時
- 最後に追加する。親が自分より大きい場合は、再帰的に入れ替える。
- シフト時(一番小さい値を取得して取り除いた時)
- 最後の要素をトップに移動する。子が自分より小さい場合は再帰的に入れ替える。
# External Merge Sort
https://en.wikipedia.org/wiki/External_sorting#External_merge_sort (opens new window)
メモリに入り切らない大きなデータを並び替える方法。2 つのフェーズがある。
- Sort Phase
- ファイルをいくつかに分割する
- 分割したファイルごとに、クイックソートなどを使ってインメモリで並び替える
- Marge Phase ソート済みの分割ファイル群を k-way merge (opens new window) (マージソート、Minimun Heapなどの組み合わせ)を使って一つのファイルに統合する