記錄下實踐過的演算法

如或長夜不安發表於2019-04-25

2019-4-24

時間測試

    const arr = [];
    for (let i = 0; i < 100000; i++) {
      const random = Math.floor(Math.random() * (100000 - 0 + 1) + 0);
      arr.push(random);
    }
    const beginTime = +new Date();
    const quickSort = this.quickSort(arr);
    const endTime = +new Date();
    console.log(`${endTime - beginTime}`);
複製程式碼

快排

  quickSort = arr => {
    if (arr.length <= 1) return arr;
    const base = arr[0];
    const left = [],
      middle = [base],
      right = [];
    for (let i = 1; i < arr.length; i++) {
      if (arr[i] === base) middle.push(arr[i]);
      else if (arr[i] < base) left.push(arr[i]);
      else right.push(arr[i]);
    }
    return this.quickSort(left).concat(middle, this.quickSort(right));
  };
複製程式碼

普通冒泡

  bubleSort = arr => {
    for (let i = 0; i < arr.length - 1; i++) {
      let isChanged = false;
      for (let j = 0; j < arr.length - i; j++) {
        if (arr[j] > arr[j + 1]) {
          [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
          isChanged = true;
        }
      }
      if (!isChanged) break;
    }
    return arr;
  };
複製程式碼

增加標誌點位冒泡

  bubleSore2 = arr => {
    let height = arr.length - 1;
    while (height > 0) {
      let position = 0;
      for (let j = 0; j < height; j++) {
        if (arr[j] > arr[j + 1]) {
          [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
          position = j;
        }
      }
      height = position;
    }
    return arr;
  };
複製程式碼

正反同時冒泡

bubleSore3 = arr => {
  let low = 0,
    high = arr.length - 1;
  while (low < high) {
    // 正向遍歷找最大
    for (let i = low; i <= high; i++)
      if (arr[i] > arr[i + 1]) this.swap(arr, i, i + 1);
    high--;
    // 反向遍歷找最小
    for (let j = high; j >= low; j--)
      if (arr[j] < arr[j - 1]) this.swap(arr, j, j - 1);
    low++;
  }
  return arr;
};
複製程式碼

堆排序

本質是遞迴構建完全二叉樹

交換二叉樹內容
swap = (arr, n, m) => {
  [arr[n], arr[m]] = [arr[m], arr[n]];
};
複製程式碼
堆排序 遞迴尋找非葉子節點
  heapSort = arr => {
    const arr_length = arr.length;
    if (arr_length <= 1) return arr;
    // 1. 建最大堆
    // 遍歷一半元素就夠了
    // 必須從中點開始向左遍歷,這樣才能保證把最大的元素移動到根節點
    for (let middle = Math.floor(arr_length / 2); middle >= 0; middle--) {
      this.maxHeapify(arr, middle, arr_length);
    }
    // 2. 排序,遍歷所有元素
    for (let j = arr_length; j >= 1; j--) {
      // 2.1. 把最大的根元素與最後一個元素交換
      this.swap(arr, 0, j - 1);
      // 2.2. 剩餘的元素繼續建最大堆
      this.maxHeapify(arr, 0, j - 2);
    }
    return arr;
  };
複製程式碼
構建最大堆
maxHeapify = (arr, middle_index, length) => {
  // 1. 假設父節點位置的值最大
  let largest_index = middle_index;
  // 2. 計算左右節點位置
  const left_index = 2 * middle_index + 1,
    right_index = 2 * middle_index + 2;
  // 3. 判斷父節點是否最大
  // 如果沒有超出陣列長度,並且子節點比父節點大,那麼修改最大節點的索引
  // 左邊更大
  if (left_index <= length && arr[left_index] > arr[largest_index])
    largest_index = left_index;
  // 右邊更大
  if (right_index <= length && arr[right_index] > arr[largest_index])
    largest_index = right_index;
  // 4. 如果 largest_index 發生了更新,那麼交換父子位置,遞迴計算
  if (largest_index !== middle_index) {
    this.swap(arr, middle_index, largest_index);
    // 因為這時一個較大的元素提到了前面,一個較小的元素移到了後面
    // 小元素的新位置之後可能還有比它更大的,需要遞迴
    this.maxHeapify(arr, largest_index, length);
  }
};
複製程式碼

相關文章