最初にクイックソートを非再帰形式 (反復クイックソート) に変換してから、setInterval を使用して for ループを置き換え、元のクイックソートを「setInterval モード」に変換することができます。
Stoimen のブログからの反復クイックソートを次に示します (元の再帰的クイックソートは同じソースから来ていると思います)。ではなく、継続渡しスタイルでコールバックを使用するように、少し変更したことに注意してくださいreturn
。
function qsort(arr, ret)
{
var stack = [arr];
var sorted = [];
while (stack.length) {
var temp = stack.pop(), tl = temp.length;
if (tl == 1) {
sorted.push(temp[0]);
continue;
}
var pivot = temp[0];
var left = [], right = [];
for (var i = 1; i < tl; i++) {
if (temp[i] < pivot) {
left.push(temp[i]);
} else {
right.push(temp[i]);
}
}
left.push(pivot);
if (right.length)
stack.push(right);
if (left.length)
stack.push(left);
}
ret(sorted);
}
この方法で関数を呼び出すことができます (例):
qsort([3,7,1,4,2,5], function(sortedarray) { console.log(sortedarray); });
この反復クイックソートを「setInterval モード」に変換するには、関数内の for ループを setInterval の呼び出しに置き換えることができます (この Stackoverflow の投稿と同様)。
を使用したクイックソートの最終バージョンは次のsetInterval
とおりです。
function qsort(arr, ret)
{
var stack = [arr];
var sorted = [];
var intervalId = 0;
intervalId = setInterval(function() {
if (stack.length) {
var temp = stack.pop(), tl = temp.length;
if (tl == 1) {
sorted.push(temp[0]);
return;
}
var pivot = temp[0];
var left = [], right = [];
for (var i = 1; i < tl; i++) {
if (temp[i] < pivot) {
left.push(temp[i]);
} else {
right.push(temp[i]);
}
}
left.push(pivot);
if (right.length)
stack.push(right);
if (left.length)
stack.push(left);
}
else if (sorted.length == arr.length) {
clearInterval(intervalId);
ret(sorted);
}
}, 0);
}
ここで何が起こるかというと、元の配列の一部がスタックに追加され (これがパーティショニング ステップです)、個別に並べ替えられます。呼び出すたびsetInterval
に、配列の異なる部分をソートしています (元の再帰的クイックソートでは、すべてのクイックソート呼び出しが配列の異なる部分を扱っていました)。setInterval
ソートされた配列が元の配列と同じサイズになると、ソートを停止する (つまり、呼び出しを停止するように指示する) ことに注意してください。それがret
コールバックを呼び出すときです。