JavaScript手寫幾種常見的排序演算法:冒泡、選擇、插入、希爾、歸併、快排
阿新 • • 發佈:2021-07-11
程式碼下載:https://github.com/pangqianjin/javascript-sort
氣泡排序
const arr = [2, 44, 1, 0, -22, 56, -78]; // arr.sort((a,b)=>a-b) function bubbleSort(arr){ let tmp; for(let i=arr.length; i>0; i--){// 較大的arr[j]會冒泡到arr的尾部 for(let j=0; j<i-1; j++){ if(arr[j]>arr[j+1]){// 前一個元素比或一個大,則向後冒泡(交換) tmp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tmp; } } } return arr; } console.log(bubbleSort(arr));// [-78, -22, 0, 1, 2, 44, 56]
選擇排序
const arr = [2, 44, 1, 0, -22, 56, -78]; function selectionSort(arr){ for(let i=0; i<arr.length; i++){ let minIndex = i;// 假設arr[i]為最小元素(即預設就是遞增) let tmp; for(let j=i+1; j<arr.length; j++){ if(arr[j]<arr[minIndex]){// 如果arr[j]比arr[minIndex]還小 minIndex = j;// 更新最小元素的下標 } } // 交換arr[i]和arr[minIndex] tmp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = tmp; } return arr; } console.log(selectionSort(arr));
插入排序
const arr = [2, 44, 1, 0, -22, 56, -78]; /* 簡單來說就是,從第二個元素開始,往前找一個合適的位置插進去 知道找到第一個比自己小的元素,然後插在它的後面 期間,當前元素與第一個比它小的元素之間的所有元素都向後移動一個位置, 直到當前元素找到第一個比他小的元素時,直接插在該元素後面就可以 */ function insertSort(arr){ let preIndex, current;// 當前元素之前的下標, 當前元素 for(let i=1; i<arr.length; i++){ preIndex = i - 1; current = arr[i]; // 當前元素向前找第一個比自己小的元素,然後插在它的後面的合適位置 while(preIndex>=0 && arr[preIndex]>current){ // 當前元素到這個第一個比自己小的元素之間的元素全部向後移動一個位置,向後擠一擠 arr[preIndex+1] = arr[preIndex]; preIndex--; } arr[preIndex+1] = current;// 找到合適位置後,當前元素直接到它的後面 } return arr; } console.log(insertSort(arr));
希爾排序
/*
希爾排序是改進的插入排序,
*/
const arr = [2, 44, 1, 0, -22, 56, -78];
function shallSort(arr){
// 增量每次/2且向下取整
for(let step=Math.floor(arr.length/2); step>0; step=Math.floor(step/2)){
// 從增量那一組開始進行插入排序,直至完畢
for(let i=step; i<arr.length; i++){
let j = i;
let current = arr[i];
// preIndex-step是與它同組的其它元素
while(j-step>=0 && arr[j-step]>current){
arr[j] = arr[j-step];
j -= step;
}
arr[j] = current;
}
}
return arr;
}
console.log(shallSort(arr));
歸併排序
const arr = [2, 44, 1, 0, -22, 56, -78];
function mergeSort(arr){
if(arr.length===0 || arr.length===1) return arr;
const middle = Math.floor(arr.length/2);
const left = arr.slice(0, middle);
const right = arr.slice(middle);
return merge(mergeSort(left), mergeSort(right));
// 輔助函式,用於將兩個數組合併為一個有序陣列,並返回
function merge(left, right){
const result = [];
while(left.length && right.length){
// 放入較小的元素,並從頭部移出
result.push(left[0]<=right[0]? left.shift(): right.shift());
}
result.push(...left, ...right);// 放入剩餘元素
return result;
}
}
console.log(mergeSort(arr));
快速排序
/*
快排是冒泡的一種改進,基於分治思想
*/
const arr1 = [2, 44, 1, 0, -22, 56, -78];
const arr2 = [2, 44, 1, 0, -22, 56, -78];
function quickSort1(arr, low, high){
let i = low, j = high, tmp;
if(i<j){
tmp = arr[i];// 選取arr[i]作為基準數
while(i!==j){
while(i<j && arr[j]>tmp) j--;
arr[i] = arr[j];
while(i<j && arr[i]<tmp) i++;
arr[j] = arr[i];
}
arr[i] = tmp;// 至此,基準數arr[i]冒泡完成
quickSort1(arr, low, i-1);// arr[i]的左側快排
quickSort1(arr, i+1, high);// arr[i]的右側快排
}
}
function quickSort2(arr){
if(arr.length===0) return arr;
const pivot = arr.pop();// 使用最後一個元素當作基準數
const left = [], right = [];
for(let i=0; i<arr.length;i++){
if(arr[i]<pivot)
left.push(arr[i]);// 小於基準數則放到left
else
right.push(arr[i]);// 大於基準數則放到right
}
// 合併left的快排結果,基準數和右側的快排結果
return quickSort2(left).concat(pivot, quickSort2(right));
}
console.log((quickSort1(arr1, 0, arr1.length-1), arr1));
console.log(quickSort2(arr2));