九種排序演算法的 JavaScript 實現

飛鴿傳書發表於2019-02-20

一、程式碼彙總(一)

by laifeipeng on 2019.02.20

  • 1、氣泡排序
  • 2、改進版氣泡排序
  • 3、選擇排序
  • 4、直接插入排序
  • 5、二分插入排序
/*
 * @Author: laifeipeng 
 * @Date: 2019-02-20 10:00:36  
 * @Last Modified by: laifeipeng
 * @Last Modified time: 2019-02-21 11:57:58
 */

/********* 1、氣泡排序 **********/
// 很常見很容易理解的排序演算法, 排序思路:遍歷陣列,每次遍歷就將最大(或最小)值推至最前。越往後遍歷查詢次數越少
const bubbleSort = arr => {
  const list = arr.slice(); //保證函式為純函式
  const len = list.length;
  for (let i = 0; i < len; i++) {
    for (let j = len - 1; j > i; j--) {
      if (list[j] < list[j - 1]) {
        [list[j - 1], list[j]] = [list[j], list[j - 1]];
      }
    }
  }
  return list;
}

/********* 2、改進版氣泡排序 **********/
// 對上述氣泡排序的一種優化, 優化思路:當一次遍歷前後陣列不產生變化時,說明該陣列已經有序,結束排序。
const bubbleSort2 = arr => {
  const list = arr.slice(); //保證函式為純函式
  const len = list.length;
  for (let i = 0; i < len; i++) {
    let exchange = false;
    for (let j = len - 1; j > i; j--) {
      if (list[j] < list[j - 1]) {
        [list[j - 1], list[j]] = [list[j], list[j - 1]];
        exchange = true;
      }
    }
    if (!exchange) return list
  }
  return list;
}

/********* 3、選擇排序 **********/
// 在無序區中選出最小的元素,然後將它和無序區的第一個元素交換位置。
const selectionSort = arr => {
  const list = arr.slice(); //保證函式為純函式
  const len = list.length;
  for (let i = 0; i < len; i++) {
    let k = i
    for (let j = len - 1; j > i; j--) {
      if (list[j] < list[k]) k = j;
    }
    if (k !== i) {
      [list[k], list[i]] = [list[i], list[k]];
    }
  }
  return list;
}

/********* 4、直接插入排序 **********/
// 每次選擇無序區第一個元素插入到有序區,並排序
const insertSort = arr => {
  const list = arr.slice(); //保證函式為純函式
  const len = list.length;
  for (let i = 1; i < len; i++) {
    const tmp = list[i];
    let j = i - 1;
    while (j >= 0 && tmp < list[j]) {
      list[j + 1] = list[j];
      j--;
    }
    list[j + 1] = tmp;
  }
  return list;
}

/********* 5、二分插入排序 **********/
// 插入排序的一種優化實現, 通過二分法減少遍歷時間(以前是從某邊開始依次比較,現在從中間開始比較,減少比較次數)
// 注意,陣列很大才能提現二分插入的優勢
const insertSort2 = arr => {
  const list = arr.slice(); //保證函式為純函式
  const len = list.length;
  for (let i = 1; i < len; i++) {
    const tmp = list[i];
    let low = 0;
    let high = i - 1;
    let j = i - 1;
    while (low <= high) {
      const mid = ~~((low + high) / 2);
      if (tmp < list[mid]) {
        high = mid - 1;
      } else {
        low = mid + 1;
      }
    }
    while (j > high) {
      list[j + 1] = list[j];
      j--;
    }
    list[j + 1] = tmp;
  }
  return list;
}
複製程式碼

2、程式碼彙總(二)

by laifeipeng on 2019.02.21

  • 6、快速排序
  • 7、原地演算法快速排序
  • 8、希爾排序
  • 堆排序、歸併排序(js實現無優勢,不作實現)
/********* 6、快速排序 **********/
const quickSort1 = arr => {
  const list = arr.slice(); //為了保證這個函式是純函式,拷貝一次陣列
  if (list.length <= 1) return list;
  const pivot = list.splice(0, 1)[0]; //選第一個作為基數,並把基數從陣列裡面刪除
  const left = [];
  const right = [];
  for (let i = 0, len = list.length; i < len; i++) { //從0開始
    if (list[i] < pivot) {
      left.push(list[i]);
    } else {
      right.push(list[i]);
    }
  }
  return [...quickSort(left), pivot, ...quickSort(right)];
}

// 上面const pivot = list.splice(0, 1)[0]; 如果想直接改為list[0],那麼後面迴圈的時候要從i=1開始
const quickSort2 = arr => {
  const list = arr.slice(); //為了保證這個函式是純函式,拷貝一次陣列
  if (list.length <= 1) return list;
  const pivot = list[0]; //選第一個作為基數
  const left = [];
  const right = [];
  for (let i = 1, len = list.length; i < len; i++) { //從1開始
    if (list[i] < pivot) {
      left.push(list[i]);
    } else {
      right.push(list[i]);
    }
  }
  return [...quickSort(left), pivot, ...quickSort(right)];
}

/********* 7、原地演算法快速排序 **********/
const quickSort = arr => {
  const list = arr.slice() // 為了保證這個函式是純函式拷貝一次陣列
  const sort = (arr, left = 0, right = arr.length - 1) => {
    if (left >= right) {//如果左邊的索引大於等於右邊的索引說明整理完畢
      return;
    }
    let i = left;
    let j = right;
    const baseVal = arr[j]; // 取無序陣列最後一個數為基準值
    while (i < j) {         //把所有比基準值小的數放在左邊大的數放在右邊
      while (i < j && arr[i] <= baseVal) { //找到一個比基準值大的數交換
        i++;
      }
      arr[j] = arr[i];    // 將較大的值放在右邊如果沒有比基準值大的數就是將自己賦值給自己(i 等於 j)
      while (j > i && arr[j] >= baseVal) { //找到一個比基準值小的數交換
        j--;
      }
      arr[i] = arr[j]; // 將較小的值放在左邊如果沒有找到比基準值小的數就是將自己賦值給自己(i 等於 j)
    }
    arr[j] = baseVal; // 將基準值放至中央位置完成一次迴圈(這時候 j 等於 i )
    sort(arr, left, j - 1); // 將左邊的無序陣列重複上面的操作
    sort(arr, j + 1, right); // 將右邊的無序陣列重複上面的操作
  }
  sort(list);
  return list;
}

/********* 8、希爾排序 **********/
// 排序思路:先將整個待排序記錄序列分割成若干個子序列,在序列內分別進行直接插入排序,待整個序列基本有序時,再對全體記錄進行一次直接插入排序。
const shellSort = arr => {
  const list = arr.slice(); //保證函式為純函式
  const len = list.length;
  let gap = ~~(len / 2);
  while (gap > 0) {
    for (let i = gap; i < len; i++) {
      const tmp = list[i];
      let j = i - gap;
      while (j >= 0 && tmp < list[j]) {
        list[j + gap] = list[j];
        j = j - gap;
      }
      list[j + gap] = tmp;
    }
    gap = ~~(gap / 2);
  }
  return list;
}
複製程式碼

希爾排序

3、效果圖

1
2

4、解答

  • 1、如何在控制檯列印出上面圖片中的彩色效果,eg:
const logStep = (i, leftArr, rightArr) => 
console.log(`%c 第${i}趟排序:%c ${arrStr(leftArr)}    %c${arrStr(rightArr)} `, 'color:green', 'color:red', 'color:blue');
複製程式碼
  • 2、交換陣列2元素:
// 交換下標為i,k的陣列元素
[list[k], list[i]] = [list[i], list[k]];
複製程式碼

相關文章