實現陣列排序的演算法很多,其中冒泡演算法是比較簡單的
冒泡的基本原理是相鄰的兩個數進行比較,按照排序的條件進行互換,例如對數值從小到大排序,
隨著不斷的互換,最大的那個值會慢慢冒泡到陣列的末端
基於這個原理我們就可以寫氣泡排序了
為了簡單起見下面的例子都是對數值陣列進行從小到大排序,先模擬一個20個字元的陣列
function getRandomArr(n) {
let arr = [];
for (let i = 0; i < n; i++) {
arr.push(~~(Math.random() * 100));
}
return arr
}
let randomArr = getRandomArr(20);
第一種冒泡演算法
從原理可知,冒泡演算法最少是需要2層迴圈的,當其中一個數值冒泡到末端時,這個數值下次就不需要參與迴圈了,這樣迴圈的範圍就會慢慢縮小,最後陣列完成排序
function bubbleSort(arr) {
let len = arr.length;
let temp;
let i = len - 1;
while(i > 0) {
for (let j = 0; j < i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
i--;//不斷縮小範圍
}
return arr;
}
console.log(randomArr)//[ 93, 72, 29, 17, 82, 26, 56, 71, 35, 48, 37, 42, 3, 11, 33, 66, 81, 53, 59, 53 ]
console.log(`bubbleSort`, bubbleSort(randomArr.concat()));//bubbleSort [ 3, 11, 17, 26, 29, 33, 35, 37, 42, 48, 53, 53, 56, 59, 66, 71, 72, 81, 82, 93 ]
在冒泡的過程中,我們可以發現,如果陣列後面部分已經排好序了,也就是不用再交換雙方的位置時,只要記錄好最後一次交換的位置,就有很大的可能縮小下次迴圈的範圍,這樣就能提高冒泡的效能(這只是猜想)
第二種冒泡演算法
function bubbleSort2(arr) {
let len = arr.length;
let i = len - 1;
let temp;
let pos;//用來記錄位置的
while (i > 0) {
pos = 0;//初始為0如果陣列一開始已經排好序了,那麼就可以很快終止冒泡
for (let j = 0; j < i; j++) {
if (arr[j] > arr[j + 1]) {
pos = j;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
i = pos;
}
return arr;
}
console.log(randomArr)//[47, 31, 85, 65, 44, 56, 54, 5, 67, 44, 76, 13, 90, 12, 83, 72, 2, 69, 58, 60]
console.log(`bubbleSort2`, bubbleSort2(randomArr.concat()));//bubbleSort2 [2, 5, 12, 13, 31, 44, 44, 47, 54, 56, 58, 60, 65, 67, 69, 72, 76, 83, 85, 90]
其實對於第一種迴圈,是從左到右進行冒泡,我們也可以從右到左冒泡,但是從右到左的方法和第一種基本就一樣了,但是我們可以在內層迴圈中實現先向左冒泡,再向右冒泡
第三種冒泡方法
function bubbleSort3(arr) {
let len = arr.length;
let low = 0;
let higth = len - 1;
let temp;
while (low < higth) {
for (let j = low; j < higth; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
higth--;
for (let j = higth; j > low; j--) {
if (arr[j] < arr[j - 1]) {
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
low++;
}
return arr;
}
console.log(randomArr)//[40, 78, 16, 97, 38, 27, 66, 44, 45, 31, 12, 1, 99, 68, 36, 42, 40, 54, 6, 42]
console.log(`bubbleSort3`, bubbleSort3(randomArr.concat()));//bubbleSort3 [1, 6, 12, 16, 27, 31, 36, 38, 40, 40, 42, 42, 44, 45, 54, 66, 68, 78, 97, 99]
最後可以結合第三種和第二種方法
第四種冒泡的方法
function bubbleSort4(arr) {
let len = arr.length;
let low = 0;
let higth = len - 1;
let temp;
while (low < higth) {
let hPos = 0;
let lPos = higth;
for (let j = low; j < higth; j++) {
if (arr[j] > arr[j + 1]) {
hpos = j;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
heigth = hPos;
for (let j = higth; j > low; j--) {
if (arr[j] < arr[j - 1]) {
lPos = j;
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
low = lPos;
}
return arr;
}
console.log(randomArr)//[40, 78, 16, 97, 38, 27, 66, 44, 45, 31, 12, 1, 99, 68, 36, 42, 40, 54, 6, 42]
console.log(`bubbleSort4`, bubbleSort4(randomArr.concat()));//[1, 6, 12, 16, 27, 31, 36, 38, 40, 40, 42, 42, 44, 45, 54, 66, 68, 78, 97, 99]
下面對這4種方法在chrome控制檯下進行一個簡單的效能測試
var randomArr = getRandomArr(10000);
console.time(`1`);
bubbleSort(randomArr.concat());
console.timeEnd(`1`);
console.time(`2`);
bubbleSort2(randomArr.concat());
console.timeEnd(`2`);
console.time(`3`);
bubbleSort3(randomArr.concat());
console.timeEnd(`3`);
console.time(`4`);
bubbleSort4(randomArr.concat());
console.timeEnd(`4`);
VM371:4 1: 329.705ms
VM371:7 2: 379.501ms
VM371:10 3: 310.843ms
VM371:13 4: 306.847ms
在經過多次測試發現一個有趣的現象執行最快的是第4種方法,最慢的是第2種,沒錯最慢的是我認為可以提高效能的第2種方法,這就相當尷尬了,不知道有哪位小夥伴可以解釋一下