先上代码(参考“五分钟学算法”)
主要分为3大部分,分别是主函数heapSort( )、堆初始化函数buildMaxHeap( )、以及最关键的自上而下的堆调整函数heapify( )。
heapSort( )函数
主要流程:
- 先建大顶堆,建完后把堆首的最大元素移至数组的末尾,则当前的最大元素已排好。
- 之后将当前数组长度-1的堆进行调整,使剩余的元素中最大的移至堆首。循环往复,直至选定数组长度为0,全部排完。
buildMaxHeap( )建堆函数
【先解释为什么循环从i=arrLen/2开始】
先上图
可以看到堆中编号为i的结点的子结点为2i+1和2i+2号。因而可以得出长度为arrLen的堆中第一个子结点不为空的结点为满足2k+1+1=arrLen或2k+2+1=arrLen的编号为k的结点。即可得出arrLen/2 -1 即为第一个子结点不为空的结点编号, 所以从这里开始建堆(即调整堆过程)。这里arrLen/2减不减1无所谓,无伤大雅,因为heapify( )函数会判断是否有子结点。
这里只从有子结点的结点开始调整是因为大顶堆结构只在乎父节点和子结点的严格大于关系,而不在乎兄弟结点间的大小关系。
heapify( )函数
heapify( )函数主要作用是自上而下地调整堆结构,使其满足堆特性。但遍历结点顺序是从下往上。
对于每一个结点,记录其子结点编号,分别判断左右子结点值是否大于父节点,找出父节点、左子结点、右子结点三个结点中的最大值,将其移至父节点的位置,这样父节点、左子结点、右子结点三个结点构成的父子树结构就满足大顶堆特性。但调整过后的左子结点/右子结点与它的子结点间的这种关系就不能被保证了,所以需要自上往下地调整被调整结点的子结点。当然,如果之前的父节点、左子结点、右子结点已经满足大顶堆特性,不需要调整,就跳过刚所说的步骤。
swap( )是交换函数,辅助作用,不用多说。