js実装:複雑さO(n^2)のソートアルゴリズム(バブルソート、単純選択ソート、直接挿入ソート)

参考ブログ:
1.各種ソートアルゴリズムまとめ(総合)
2. 【アルゴリズムまとめ】ソートアルゴリズムトップ10

(以下のアルゴリズムのソート方向は小さいものから大きいものとする。配列の要素数はnであるとする。)
ここに画像の説明を挿入

1. バブルソート

1. 原則:

——配置する要素の数は n 個
(1) まず、n 個の要素のうち、最大の要素を最後に配置し、配置する要素の数は n-1 個となります。【要素の位置を決定する】
(2) n-1 個の要素のうち 2 番目に大きい要素を配置する要素の最後に配置し、配置する要素の数は n-2 個となります。[2 つの要素の位置が決まります]
...
(n-1) 並べ替える要素の数が 1 つになるまで、上記の手順を n-1 回繰り返します。[n-1 個の要素の位置が決まっているので、残りの要素を決める必要はありませんよね?サイクルを保存しました]

例: arr=[2,6,4,10,3]
(1) 時間: 2 は 6 より小さい、交換なし、6 は 4 より大きい、交換なし、6 は 10 より小さい、交換なし、10 はより大きい3、交換
この時点で配列は [2,4,6,3, 10 ] となり、10 の位置が決まります。
(2) パス: 2 が 4 より小さい、交換しない; 4 が 6 より小さい、交換しない; 6 が 3 より大きい、交換する; このとき、配列は次のようになります: [2,4,3
, 6,10』の6の位置 大丈夫!
3 回目: 2 が 4 より小さいので交換しない; 4 が 3 より大きいので交換する;
このときの配列は [2,3, 4,6,10 ] となり、4 の位置が決まります。
ステップ(4): 2 は 3 より小さいので交換しない
このとき、配列は [2, 3, 4, 6, 10 ] となり、3 の位置が決まります。
2の位置は自然に決まる!

2. コード:

ソート対象の要素の最大値を最後に置くのは、実際には隣接する要素を2つずつ比較し、arr[j]>arr[j+1]であれば位置を入れ替えることになります。j+1==arr.length-1まで、サイクルは終了します

<script>
	let arr = [2,6,4,10,3];
	console.log(bubbleSort(arr));
	
	/**
	 * @param {array} arr
	 */
	function bubbleSort(arr){
    
    
		// 要确定原数组中,哪一个元素的位置
		for(let i=arr.length-1; i>0; i--){
    
    
			// 待排元素的范围:为什么 j 要小于i,为了保证 j+1 不越界
			for(let j=0; j<i; j++){
    
    
				if(arr[j]>arr[j+1]) swap(arr, j, j+1);
			}
		}
		return arr;
	}
	
	/**
	 * @param {array} arr
	 * @param {int} i
	 * @param {int} j
	 */
	function swap(arr, i, j){
    
    
		let temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
</script>

要素間の位置の交換は、並べ替えアルゴリズムでは非常に一般的です。そのため、ここではコードの再利用性を高めるために別途スワップ関数として記述します。

3. 最適化

配列が [2,10,3,4,5,6] などの比較的順序付けられた配列に置き換えられた場合、何度も走査する必要がありますか?
明らかに、この配列を走査する必要があるのは 1 回だけであり、すでに整っています。
[思考]: 配列がすでに整った場合に、ループを終了するためにフラグの変更を追加できますか。

<script>
	function bubbleSort(arr){
    
    
		for(let i=arr.length-1; i>0; i--){
    
    
			let change = false; // 标志位
			for(let j=0; j<i; j++){
    
    
				if(arr[j]>arr[j+1]){
    
    
					swap(arr, j, j+1);
					change = true; // 修改标志位
				}
			}
			if(change == false) break; // 标志位。结束循环
		}
		return arr;
	}
</script>

[2,10,3,4,5,6]
最初のループが終了した後、配列はすでに整っていて、
2 番目のループが終了した後、フラグ ビットは変更されないため、ループは終了し、
3 番目のループは変更されます。実行されません。

2. 簡易選択ソート

1. 原則

これは実際にはバブル ソートに非常に似ており、2 つのペア間の比較でもありますが、この時点では交換されずに記録されます。未ソートのシーケンス全体を走査した後、未ソートのシーケンスで最大の値を見つけ
ます交換。
[選択ソートはバブルソートを改良したものと考えられます]

仮定: 配列の先頭はソートされたシーケンスで、後部はソートされていないシーケンスです。
小さい値から大きい値の順にソートされるため、次のシーケンスから最小値を選択し、ソートされたシーケンスの最後に配置します (つまり、ソートされたシーケンスの最後の要素と交換します)。 例: arr=[
4,3 ,2,5,6]
(1) 時間: ソートされたシーケンスは空、[]、ソートされていないシーケンスは [4,3,2,5,6]、最小値を選択: 2、ソートされたシーケンスに従います。の最後の要素、すなわち 4 と交換されます。[2,3,4,5,6]
(2) 時間: ソートされたシーケンスは空です、[2]、ソートされていないシーケンスは次のとおりです: [3,4,5,6]、最小値を選択します: 3、次に従いますソートされたシーケンスの最後の要素、つまり 3 と交換されます。[2,3,4,5,6]
(3) 時間: ソートされたシーケンスは空です、[2,3]、ソートされていないシーケンスは次のとおりです: [4,5,6]、選択された最小値: 4、次に従いますソートされたシーケンスの最後の要素、つまり 4 と交換されます。[2,3,4,5,6]
(4 番目の) トリップ: ソートされたシーケンスは空です、[2,3,4]、ソートされていないシーケンスは次のとおりです: [5,6]、選択された最小値: 5、フォローしますソートされたシーケンスの最後の要素、つまり 5 と交換されます。[2,3,4,5,6]
(5 番目) トリップ: ソートされたシーケンスは空です、[2,3,4,5]、ソートされていないシーケンスは次のとおりです: [6]、最小値を選択します: 6、次に従いますソートされたシーケンスの最後の要素、つまり 6 と交換されます。[2,3,4,5,6]

配列全体がソートされている場合でも、ソートされていないシーケンスが空でない限り、最小値が検索されます。
バブルソートに改善点があるとすれば、交換回数を減らすことでしょうか?

2. コード

function selectSort(arr){
    
    
	// 已排序序列的右区间+1。
	// i是从0开始,已排序右区间最开始应该理解成-1?
	for(let i in arr){
    
    
		// 假设未排序序列的第一个元素为min
		let min_index = i;
		// 未排序序列的左区间
		for(let j=i; j<arr.length; j++){
    
    
			min_index = arr[j] < arr[min_index] ? j : min_index;
		}
		swap(arr, i, min_index);
	}
	return arr;
}

3. 挿入ソート

1. 原則

これは選択ソートとよく似ており、配列をソートされたシーケンスとソートされていないシーケンスの 2 つの部分に分割します。ただし、ここでは最初の要素はデフォルトでソートされており、前の選択ソートはデフォルトのソート順であり、空です(選択ソートでは、ソート順の位置は一度決定されると変更されないため)。

1. ソートされていないシーケンスの最初の要素のキーを取り出し、ソートされたシーケンスの後ろから前に向かって走査し、キーより大きい要素arr[j]が見つかったら、それを 1 ビット後ろに移動します (キーは arr [ j] より小さいため、キーのためのスペースを確保するために前に配置する必要があります)。
2. キーより小さい要素 **arr[j]** が見つかるまで、キーは arr[j] の後ろに配置されます。arr[j+1]=key
3. ソートされたシーケンスを走査した後に key より小さい値が見つからない場合は、key を先頭に配置する必要があることを意味します。

2. コード

function insertSort(arr){
    
    
	// 未排序序列
	for(let i=1; i<arr.length; i++){
    
    
		// 记录下要排序的元素
		let key = arr[i];
		// 已排序序列
		for(var j=i-1; j>=0 && key < arr[i]; j--){
    
    
			arr[j+1] = arr[j];
		}
		// 跳出循环的条件:j<0 || 遇到比key小的值
		arr[j+1] = key;		
}

おすすめ

転載: blog.csdn.net/qq_38432089/article/details/124220384