参考ブログ:
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;
}