排序算法之堆排序!
排序算法之堆排序!
月伴飞鱼堆是一种特殊的树,只要满足这两点,它就是一个堆。
- 堆是一个完全二叉树。
- 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。
对于每个节点的值都大于等于子树中每个节点值的堆,叫做大顶堆。
对于每个节点的值都小于等于子树中每个节点值的堆,叫做小顶堆。
一般升序用大根堆,降序就用小根堆。
如何实现一个堆
完全二叉树比较适合用数组来存储。
用数组来存储完全二叉树是非常节省存储空间的。
因为不需要存储左右子节点的指针,单纯地通过数组的下标,就可以找到一个节点的左右子节点和父节点。
比如查找数组arr中某个数的父结点和左右孩子结点,比如已知索引为i的数,那么:
父结点索引:
(i-1)/2左孩子索引:
2*i+1右孩子索引:
2*i+2所以堆的定义性质:
大根堆:
arr(i)>arr(2*i+1) && arr(i)>arr(2*i+2)小根堆:
arr(i)<arr(2*i+1) && arr(i)<arr(2*i+2)
堆排序基本步骤
首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端。
将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1。
将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组。
以下将针对数组
arr[1,2,5,4,3,7]进行大顶堆的数据结构转换。从最后一个非叶子结点开始(第一个非叶子结点
arr.length/2-1=5/2-1=1,也就是索引为2的结点)。
- 从右至左,从下至上进行调整。
由于[5,7]中7元素最大,5和7交换。
最后一个非叶子结点索引减1,找到第二个非叶结点(索引1),由于[4,3,2]中4元素最大,2和4交换。
非叶子结点索引减1,找到第三个非叶结点(索引0),由于[4,1,7]中7元素最大,1和7交换。
这时,交换导致了子根[1,5]结构混乱,继续调整,[1,5]中5最大,交换1和5。
此时,我们就将一个无序序列构造成了一个大顶堆。
将堆顶元素与末尾元素进行交换,使末尾元素最大。
然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。
最后,就实现了堆排序。
1 | import java.util.Arrays; |












