给定一个整形数组a[]={16,7,3,20,17,8},对其进行堆排序。 首先根据该数组元素构建一个完全二叉树,得到
然后需要构造初始堆,则从最后一个非叶节点开始调整,调整过程如下:
![](https://i-blog.csdnimg.cn/blog_migrate/be4112186c9ee6843754058bc9680d64.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/472ab42d1657bef1923d7823835b002e.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/0ef795ebf171fdbcd4e6f8a6227f5297.jpeg)
20和16交换后导致16不满足堆的性质,因此需重新调整
![](https://i-blog.csdnimg.cn/blog_migrate/1af7ac5d3cc4600bb396348ac44eb9cd.jpeg)
这样就得到了初始堆。
即每次调整都是从父节点、左孩子节点、右孩子节点三者中选择最大者跟父节点进行交换(交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整)。有了初始堆之后就可以进行排序了。
![](https://i-blog.csdnimg.cn/blog_migrate/a975142be7cd47b6190e7610c7b25781.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/cf65ac3aab157f1e3a835fdaa375b2a1.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/7e7216ae484088456b0e4057f171a2f1.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/13fcfbf89cd397f05cc8d7923fe59af5.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/db974ea48e04a2fb20cec005251e9246.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/d8cd7d07e78610d8d4b30406e1076944.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/7026cd175b689cbc1741585fe3a8c8c3.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/471643fe41219694e351266b923a7b52.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/b82775a75d194a52f1faca1d595d0b08.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/f59c8a69dd6b220a5afbddb13a113190.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/d31f0963160f5aa19f502b97d23aba66.jpeg)
这样整个区间便已经有序了。从上述过程可知,堆排序其实也是一种选择排序,是一种树形选择排序。只不过直接选择排序中,为了从R[1...n]中选择最大记录,需比较n-1次,然后从R[1...n-2]中选择最大记录需比较n-2次。事实上这n-2次比较中有很多已经在前面的n-1次比较中已经做过,而树形选择排序恰好利用树形的特点保存了部分前面的比较结果,因此可以减少比较次数。对于n个关键字序列,最坏情况下每个节点需比较log2(n)次,因此其最坏情况下时间复杂度为nlogn。堆排序为不稳定排序,不适合记录较少的排序。 上面描述了这么多,简而言之,堆排序的基本做法是:首先,用原始数据构建成一个大(小)堆作为原始无序区,然后,每次取出堆顶元素,放入有序区。由于堆顶元素被取出来了,我们用堆中最后一个元素放入堆顶,如此,堆的性质就被破坏了。我们需要重新对堆进行调整,如此继续N次,那么无序区的N个元素都被放入有序区了,也就完成了排序过程。