【数据结构】之堆排序

本文从以下几个方面阐述堆排序:

1 何谓“堆”?

2 完全二叉树的特点

3 堆排序如何实现?

4 树的存储

5 PriorityQueue内部如何实现堆排序?

6 总结。

 

 

1 何谓“堆”?

  一个序列满足以下定义,我们把它称作“堆”:

  a)以完全二叉树的结构存储 ;b)所有非终端节点的值均不大于或者不小于其左右孩子节点的值。

注意:此处用的是“不大于或者不小于”,说明节点等于它的左或右孩子也是可以的。“不大于”时为小顶堆,“不小于”时为大顶堆。

 

 

   如图:
 
 

 注意:大顶堆的堆顶元素并不一定是最大的。只要满足了上述情况即可以成为“堆”。要使堆顶元素最大或者最小,则需要用到堆排序,完成的就是每次得到最大(或者最小)堆顶元素并输出得到有序序列的过程。

 

 2 完全二叉树

从上面对“堆”的定义可知:堆首先是一棵完全二叉树,那么在分析堆排序之前我们有必要先来了解以下什么是完全二叉树:

 

定义:深度为k,有n个节点的二叉树,当且仅当其每一个节点都与深度为k的满二叉树中编号从1~n的节点一一对应,这样的树称为完全二叉树。(此处不详谈,对此不理解的读者请自己百度之)

 

完全二叉树的特点:

 1)叶子节点只可能在层次最大的两层上出现。

 2)当右分支下的子的最大层次为L时,左分支下的子孙的最大层必为L或者L+1。

 

完全二叉树的性质:

1)具有n个节点的完全二叉树的深度为[logN]+1.

2) 节点从1~n,若节点i>1,则双亲是节点[i/2](取整);若2i>n,则无左孩子,否则左孩子为2i;若2i+1>n,则无右孩子,否则右孩子为2i+1.

 

3 堆排序如何实现?

 

步骤:a)初始建堆:即由一个无序序列建立一个堆。b)筛选重新建堆,保证每次得到的堆顶元素为最大或者最小,输出堆顶元素,重复操作,得到有序序列。

 

首先我们来看如何筛选建堆?假设现在已经有一个建立好的小顶堆,输出堆顶元素后,我们如何把剩余的元素重新建一个堆,使得堆顶元素最小呢?

 

看图:

 方法如下:输出13后,把最后一个元素80换到堆顶位置,因为80>27,则又需交换27与80的位置,又发现80>65,因此又需交换80与65的位置,最后得到:



 此即为输出13之后对剩余元素的重新筛选建立堆。

 

现在再让我们回到前面,我们如何从一个无序序列得到初始的小顶堆呢?其实初始建堆就是把上述过程反复的执行。首先把无序序列构造为一棵完全二叉树,从下往上比较每一个节点与其双亲节点,小的值上移,如此遍历完整棵树,则得到了一个初始的小顶堆。

 

注:笔者表达能力有限,对此不清楚的读者请翻看数据结构书......

 

 

4 树的存储。

   了解了堆排序的原理后,这样的过程如何在代码中实现呢?我们先得知道树的存储结构:

  1)双亲表示法。即数组存储。用一组连续的空间存放树的节点,每个节点中设一个指示器指向双亲节点在数组中的位置。

      优劣:找双亲容易,但要找某一个节点的儿子则需要遍历整个数组。

  2)孩子表示法:即数组与链表结合存储。每个节点放在顺序存储的结构中,每个节点中又包括一个指向其孩子的指针。大概形式如下图:



 3)孩子兄弟表示法:即链表存储。(此处详情略)

 

5 PriorityQueue内部如何实现堆排序:

   此处在我的另外一篇博客http://792881908-qq-com.iteye.com/blog/1454401 中有解析。

 

6 总结:

  堆排序是一种在树形选择排序上的优化,有它一定的优势,但在记录较少的文件中并不提倡,对于它和其他排序方式性能的比较还有待进一步分析。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值