堆排序HeapSort及可视化

开始

堆排序一种比较复杂的排序算法,它主要用到堆(Heap)这一数据结构。javascript

堆(Heap)是二叉树的一类,彻底二叉树,它的特色是:html

  • 除最后一层外,其余层节点都是满的
  • 最后一层节点能够不满
  • 最后一层节点从左向右填充
  • 左节点和右节点的大小关系没有限制

以下图 java

彻底二叉树

堆又分为git

  • MaxHeap, 父节点值大于子节点值
  • MinHeap, 父节点值小于子节点值

堆排序的主要过程(以MaxHeap为例):github

  • 将数组构造为MaxHeap,父节点为最大值
  • 将父节点与末尾元素交换,
  • 将剩余的元素再次构建为MaxHeap
  • 重复二,三步,至只剩一个元素

构造MaxHeap的过程

从第一个非叶子结点开始,从下至上,从右至左,对每个非叶子结点作shiftDown操做,因此shiftDown是一个关键过程。算法

其中,能够利用数组结构来表示Heap,已知节点索引i, 其节点关系有segmentfault

  • 父节点, Math.floor((i - 1) / 2)
  • 左节点,2 * i + 1
  • 右节点,2 * i + 2
  • 第一个非叶子结点,arr.length/2 - 1

推荐实现

参考中都给出了一些实现,不过,对于heapifyDown方法,推荐以下实现,来源于参考4,我的以为从理解和结构上看都比较好。api

heapifyDown(customStartIndex = 0) {
    // Compare the parent element to its children and swap parent with the appropriate
    // child (smallest child for MinHeap, largest child for MaxHeap).
    // Do the same for next children after swap.
    // 当使用Heap排序时,顶部元素被赋值为尾元素,此时,须要从顶向下从新建堆
    let currentIndex = customStartIndex;
    let nextIndex = null;

    // 假设在MaxHeap中,节点初始关系为P->C->C1, 首先进行堆构建,
    // 继续假设子节点C大于父节点P, 则须要将子节点C与父节点P进行交换,
    // 父节点P下沉作为子节点,此时新的节点关系为C->P->C1,
    // 若是C1>P,则须要继续将节点P下沉,变为C->C1->P
    // 以上例子说明,只要一个节点位置发生变化,就须要逐层向下递归,以确保节点关系正确
    // 此处的while循环就是这个道路,虽然上面只有一个参数customStartIndex, 但考虑
    // 节点可能互换,就须要进行向下递归,把当前节点的全部节点都进行一次比较
    while (this.hasLeftChild(currentIndex)) {
      // 与二叉树不一样,Heap结构中,左右节点值的关系是不固定的
      // 左节点可能小于右节点,也可能大于右节点,只能保证左右节点和父节点的值大于关系固定
      // 取左右节点中,较大(For MaxHeap)或较小(For MinHeap)的值与父节点进行交换
      if (
        this.hasRightChild(currentIndex)
        && this.pairIsInCorrectOrder(this.rightChild(currentIndex), this.leftChild(currentIndex))
      ) {
        nextIndex = this.getRightChildIndex(currentIndex);
      } else {
        nextIndex = this.getLeftChildIndex(currentIndex);
      }

      // 若是节点大小关系正确,说明不用进行节点互换,直接退出,
      // 不然进行递归检测与修正
      if (this.pairIsInCorrectOrder(
        this.heapContainer[currentIndex],
        this.heapContainer[nextIndex],
      )) {
        break;
      }

      this.swap(currentIndex, nextIndex);
      currentIndex = nextIndex;
    }
  }
复制代码

总结

参考1,2里图文都很详细,推荐,其中实现形式,能够本身再整理优化下数组

另外,我找到一个可视化工具,不只有Heap Sort, 还有Binary Tree,能够上手测试,亲身感觉,强烈推荐: btv.melezinek.cz/binary-heap…bash

稳定性

堆排序是一种不稳定的排序方法, 对于相同的关键字可能出现排在后面的关键字被交换到前面来的状况

参考

  1. segmentfault.com/a/119000001…
  2. www.e-learn.cn/content/qit…
  3. 五分钟学算法
  4. Heap.js
  5. Heap Visualiser