堆排序 [Algorithm]

来源:互联网 发布:php直销系统源码 编辑:程序博客网 时间:2024/06/06 06:53

老生常谈:

      插入排序最坏情况O(n2), 其内循环比较紧凑,对于小规模输入是一个快速的原地(数组中某个局部)排序算法。归并排序有着渐进运行时间nlgn时间,merge不在原地操作(merge最用在整个数组中)。堆排序正是前面两者优点的整合,在nlgn时间,对n个数进行原地排序[1]

 分析

      堆是典型的完全二叉树,n个元素的堆数组中。

      n/2(隐式下取整)+1 开始是叶子节点。证明:对于任意下标为i(从0开始)的非叶子节点,有性质:2*i+1, 2*i+2为其左右孩子,有2*i+1 <= n  and  2*i+2 <= n, 则最后一个非叶子结点为(int)n/2。下一个n/2+1为叶子节点。 

      堆排序关键是一个调整函数,每次递归调整某个子树,使其保持最大堆或者最小堆的性质,这个函数的一个细节是作用范围,以函数参数的形式传入。

 

代码实现

      程序中,通过宏在debug模式下,增加了一些脚手架”,所谓的脚手架就是程序中加入输出以观察运行过程,度量代码以及组件测试的方法[2]。这种辅助工具,有点像工业制造中的工装,工装”即生产过程工艺装备指制造过程中所用的各种工具的总称。包括刀具/夹具/模具/量具/检具/辅具/钳工工具/工位器具等[3]

      有了脚手架的代码,看上去就不那么整齐,就像去工地一样,布满工装,肯定没有装修好的高楼大厦整洁干净~ 下面是整个代码:

 

自己写的heap_sort与STL的sort_heap比,效率差了点(主要是验证思路),实验结果如下:

后记

     建堆有两种方案:一种思路从最后一个父亲结点,逆序调整堆;另一种思路是从第二个元素开始插入法建堆。STL中是插入法建堆。插入法建大顶堆的思路:先将一个最小数字放到堆末尾,此时满足最大堆性质;然后循环增加键值,保持大顶堆的性质。

始终有个疑问,这种插入法建立的堆是否是唯一的?测试结果:对于一堆相同的输入,插入法建堆,调整方式建堆,和STL建堆 结果都不一样~

代码如下:

 

add - 2010/12/8 p.m

 

[1] 算法导论 - 堆排序

[2] 编程珠玑 - 程序员的忏悔

[3] 百度百科 - 工装 http://baike.baidu.com/view/907594.htm

add - 2011/9/21 p.m

Find_Top_K问题:数组N中寻找最大的K个元素:

用前K[0 - k-1]个元素,建立小顶堆K-Min-Heap;

遍历K - N-1元素,和堆顶元素比较:

小于跳过,

大于则替换堆顶元素,调整K-Min-Heap结构使之保持小顶堆特性;

K-Heap的操作时间为log2(k)


原创粉丝点击