博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
堆排序
阅读量:6481 次
发布时间:2019-06-23

本文共 3109 字,大约阅读时间需要 10 分钟。

一、简介

堆排序可以分为两个阶段:构造堆下沉排序两个阶段。

构造堆:将原始数组重新组织为一个堆。

下沉排序:从堆中按递减顺序取出所有元素并得到排序结果。

 

二、实现

1、堆排序

中规中矩的方法:

从左向右遍历整个数组,用swim方法保证当前位置左侧的所有元素已经是堆有序的即可。

就像连续向优先队列中插入元素一样。可以在NlogN成正比的时间内完成这个任务。

 

更加高效的方法:

从右至左用sink方法构造子堆,数组的每个位置都是一个子堆的根节点,sink对这些子堆也适用。

如果一个节点的两个子节点都是堆的根节点了,那么对该节点调用sink函数可以将以这个节点为根节点的树变为堆。

这个过程会递归地建立起堆的秩序。这个过程只需扫描数组中的一半元素,因为大小为1的子堆可以跳过。

 

2、下沉排序

将堆最大的元素删除,然后放入堆缩小后数组中空出的位置。

 

 代码实现如下:

public static void sort(Comparable[] pq) {        int n = pq.length;        for (int k = n/2; k >= 1; k--)            sink(pq, k, n);        while (n > 1) {            exch(pq, 1, n--);            sink(pq, 1, n);        }    }

 

 

基础函数:

  /***************************************************************************    * Helper functions to restore the heap invariant.    ***************************************************************************/    private static void sink(Comparable[] pq, int k, int n) {        while (2*k <= n) {            int j = 2*k;            if (j < n && less(pq, j, j+1)) j++;            if (!less(pq, k, j)) break;            exch(pq, k, j);            k = j;        }    }   /***************************************************************************    * Helper functions for comparisons and swaps.    * Indices are "off-by-one" to support 1-based indexing.    ***************************************************************************/    private static boolean less(Comparable[] pq, int i, int j) {        return pq[i-1].compareTo(pq[j-1]) < 0;    }    private static void exch(Object[] pq, int i, int j) {        Object swap = pq[i-1];        pq[i-1] = pq[j-1];        pq[j-1] = swap;    }

 

 

尽管sort函数中,两个循环任务不同,第一个循环构造堆,第二个循环在下沉排序中销毁堆。

这两个循环都是基于sink方法,这个实现跟优先队列的API区分开来是为了突出这个排序算法的简洁性。

 

三、性能分析

结论1:用下沉sink操作构造N个元素堆,只需要少于2N次比较以及少于N次交换。

证明:

It suffices to prove that sink-based heap construction uses fewer than n exchanges because the number of compares is at most twice the number of exchanges. For simplicity, assume that the binary heap is perfect (i.e., a binary tree in which every level is completed filled) and has height h.

 

Alternate heapify analysis

We define the height of a node in a tree to be the height of the subtree rooted at that node. A key at height k can be exchanged with at most k keys beneath it when it is sunk down. Since there are 2hk nodes at height k, the total number of exchanges is at most:

 

Alternate heapify analysis

The first equality is for a nonstandard sum, but it is straightforward to verify that the formula holds via mathematical induction. The second equality holds because a perfect binary tree of height h has 2h+1 − 1 nodes.

Proving that the result holds when the binary tree is not perfect requires a bit more care. You can do so using the fact that the number of nodes at height kin a binary heap on n nodes is at most ceil(n / 2k+1).

 

结论2:将N个元素排序,堆排序只需少于(2NlogN + 2N)次比较,以及少于一半次数(NlogN + N)的交换。

证明:

2N项来源于堆的构造,证明看结论1。

2NlogN来源于每次下沉操作最大可能2logn(1 <= n <= N-1)次比较。即2*(logN-1 + log N-2 + …… + log1)~2NlogN

 

结论3:堆排序在排序复杂性的研究中有有重要的地位。

堆排序是唯一能够同时最优地利用空间和时间的方法。在最坏的情况也能保证~2NlogN次比较和常数级别额外空间。

但是,堆排序无法利用缓存,堆排序中数组元素很少与相邻的其他元素进行比较,因此缓存未命中的概率远远大于大多数比较都在相邻元素之间的算法。

 

转载于:https://www.cnblogs.com/songdechiu/p/6736502.html

你可能感兴趣的文章
数据库运维体系_SZMSD
查看>>
js的AJAX请求有关知识总结
查看>>
三分 POJ 2420 A Star not a Tree?
查看>>
修改OBS为仅直播音频
查看>>
OCA读书笔记(3) - 使用DBCA创建Oracle数据库
查看>>
Python基础进阶之路(一)之运算符和输入输出
查看>>
阻塞非阻塞异步同步 io的关系
查看>>
ClickStat业务
查看>>
spring3.0.7中各个jar包的作用总结
查看>>
Windows 10 /win10 上使用GIT慢的问题,或者命令行反应慢的问题
查看>>
Windows平台分布式架构实践 - 负载均衡
查看>>
iOS自定制tabbar与系统的tabbar冲突,造成第一次点击各个item图片更换选中,第二次选中部分item图片不改变...
查看>>
我的路上
查看>>
DB2与oracle有什么区别
查看>>
创建一个多级文件目录
查看>>
svn status 显示 ~xx
查看>>
常用HiveQL总结
查看>>
[转]使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(三)-- Logger
查看>>
Security updates and resources
查看>>
打印图片
查看>>