RCIE-ジャンクのコード屋

主に自分のためにコーディングのTIPSを蓄積しています。

(JavaScript)安定なソートを実装する

作ったもの

Javascriptの仕様によると、sort()は、元の配列の前後関係を保障しない不安定なソートだそうです。
安定なソートも欲しいので、実装してみました。

コード

function msort(ary){
	let len = ary.length;
	let block = 8; // ソート済ブロックの大きさ
	for(let i = 0; i < len; i += block){
		// 少ない要素の比較なら、挿入ソートが速い
		let done = 1;
		let end = Math.min(i + block, len);
		let a = i + 1;
		while(a < end){
			while(a > i){
				if(ary[a-1] > ary[a]){
					let t = ary[a-1]; ary[a-1] = ary[a]; ary[a] = t;
					a--;
				}else{break;}
			}
			done++;
			a = i + done;
		}
	}
	if(block >= len){return;}
	let buff = new Array(len);
	let src = ary;
	let dst = buff;
	let srcIsAry = true;
	while(block < len){
		for(let i = 0; i < len;){
			let beg = i;
			let mid = Math.min(i + block, len);
			let end = Math.min(mid + block, len);
			for(let a = beg, b = mid; i < end; i++){
				if(a === mid){
					dst[i] = src[b];
					b++;
					continue;
				}else if(b === end){
					dst[i] = src[a];
					a++;
					continue;
				}
				if(src[a] > src[b]){
					dst[i] = src[b];
					b++;
				}else{
					dst[i] = src[a];
					a++;
				}
			}
		}
		block *= 2;
		let tmp = src; src = dst; dst = tmp;
		srcIsAry = !srcIsAry; // srcとdstを入れ替えながら処理する
	}
	if(!srcIsAry){ // src が 元データならコピー処理をスキップ
		for(let i = len; i-->0;){
			dst[i] = src[i];
		}
	}
}

補足

アルゴリズムは、安定ソートの代表のマージソートを使用しました。小さな要素数(≦10)のデータをソートする際には、挿入ソートの方が速いようなので、途中までは挿入ソートを使い、途中からマージソートに切り替えます。

10万要素のソートを行った場合
標準ソート:50ms
自作ソート:120ms
となり、2倍ほど遅いですが、実用上は許容範囲かと。(実行環境はGoogle Chrome