Skip to content

堆排序

大顶堆

大顶堆

下标为 i 的节点:

  • 其父节点的坐标为 (i - 1) >> 1
  • 左孩子 i * 2 + 1
  • 右孩子 i * 2 + 2

小顶堆

小顶堆

js
Array.prototype.heapSort = function () {
  const arr = this;
  let len = arr.length;

  function swap(a, b) {
    const tmp = arr[a];
    arr[a] = arr[b];
    arr[b] = tmp;
  }

  /**
   * 维护堆的性质
   * @param {number} i 当前在维护第几个节点
   */
  function heap(i) {
    let maxIndex = i;
    let lIndex = i * 2 + 1;
    let rIndex = i * 2 + 2;
    // 找到 [当前节点 i, 左节点 lIndex,右节点 rIndex] 中最大的
    if (lIndex < len && arr[lIndex] < arr[maxIndex]) {
      maxIndex = lIndex;
    }
    if (rIndex < len && arr[rIndex] < arr[maxIndex]) {
      maxIndex = rIndex;
    }
    // 如果不满足堆堆性质(孩子节点存在大于父节点的),执行交换,同时递归的维护后面的节点
    if (i !== maxIndex) {
      swap(i, maxIndex);
      heap(maxIndex);
    }
  }

  /**
   * 建堆的过程需要从最后一个非叶子节点开始,逐个向前调用 heap 方法维护堆的性质
   * 最后一个叶子节点的下标为 `len - 1`,它的父节点的下标为 `(len - 1 - 1) / 2`
   */
  function buildHeap() {
    for (let i = (len - 1 - 1) >> 1; i >= 0; i--) {
      heap(i);
    }
  }
  buildHeap();
  console.log(arr);

  for (let i = len - 1; i > 0; i--) {
    swap(0, i);
    len--;
    heap(0);
  }
  console.log(arr);
};