我们可以把任意优先队列编程一种排序方法。将所有元素插入一个查找最小元素的优先队列,然后再重复调用删除最小元素的操作来将他们按顺序删除。用无序数组实现的优先队列这么做相当于一次选择排序。用基于堆的优先队列排序相当于我今天要说的——堆排序。
堆排序可以分为两个阶段:①堆的构造 ②下沉排序
堆的构造:①用swim()可以在与NlogN成正比的时间内完成这项操作。只需从左至又遍历数组,②挨个把元素插入到堆中。
②用sink()只需少于2N次比较和小于N次交换。显然下沉操作更加高效。将每个节点下沉排序,即通过此算法可以使只有目前节点作为根节点的堆进行有序化,显然数组中N/2之后的节点都不存在新的子叶,故下沉函数从N/2以前从右至左挨个实现当前子堆的有序化,最终可实现整个堆的有序化。
下沉排序:将堆中最大元素放到最后,使堆的规模减小一,再循环次步骤,直至堆中不存在元素。
堆排序的代码实现:
public static void sort(Comparable [] a) {
int N=a.length;
for(int k=N/2;k>=1;k--) { //构造堆,即实现堆的有序化
sink(a,k,n);
}
while(N>1) {
exch(a,1,N--); //交换根节点和堆中最后一个元素的位置,即将目前堆中最大的元素放于对的最后
sink(a,1,N); //重新进行堆的有序化
}
}
性能:将N个元素排序,堆排序只需要少于(2NlgN+2N)次比较(以及一半次数的交换)。
堆排序是我们所知的唯一能够同时最优地利用空间和时间的方法。
但是现代系统中应用不多,因为它很少和数组中相邻的元素比较,即无法利用缓存,所以缓存未命中的次数要远高于很多算法。
另一方面它也十分重要,因为它能在插入操作和删除最大元素操作的混合的动态场景中保证对数级别的运行时间。
来源:oschina
链接:https://my.oschina.net/u/3786691/blog/1629912