选择排序(三)--堆排序

来源:互联网 发布:瑞文戴尔之剑数据库 编辑:程序博客网 时间:2024/04/28 01:30

一、堆排序思想 (要和shell排序区别)
   堆,是一棵完全二叉树,(完全二叉树概念:只有最后两层可以是业界点,而且最底层的叶节点都在左侧,图在上一篇日志上有)
   堆可以用数组来描述,在排序中强调的是 大根堆(最大值在树根),将大根堆的的根部值 和 无序数组的最后一个数交换,然后重新排序新的无序堆为 大根堆。


      具体排序思想:将待排序区分为无序区和有序区,无序区在前,有序区在后。未排序前无序区为整个待排序区间,没有有序区。
     排序的过程是,不断地将无序区构造成一个大根堆,这样无序区中的最大元素便被放置在了数组的最前面即根的位置,然后将无序区的第一个元素与最后一个元素交换,此动作将无序区的长度缩小一,将有序区的长度扩大一,即有序区前进一,无序区向前退一。然后将新的无序区(由于根节点的变化,此时很可能已经不是大根堆)重新调整为大根堆,等待下一次的交换。如此往复,不断地将无序区的最大元素添加到有序区的前面,同时缩小无序区,直到有序区占满待排序区为止。

这样,还剩下两个问题: 1.如何将一个交换后的无序区调整为大根堆; 2.如何在排序之前建立那个初始的大根堆。而第二个问题是可以通过第一个问题的解决而解决的。
      1.如何将一个交换后的无序区调整为大根堆?
      由于进行元素交换前,无序区是一个大根堆,即左子树和右子树都是大根堆,所以根节点变化后左右子树仍然都是大根堆,无序区里的最大元素一定在新根节点、左右子树的根节点这三个结点里。先存储新的根节点的值以待后用。如果新的根结点最大,说明已经是大根堆,调整完毕; 
      否则比较左右子树根节点,找出较大的,它是无序区现存的最大元素,应该作为新的大根堆中的根,所以将此节点上调至根节点位置,接下来就只需要调整此结点原来所在的子树为大根堆即可(因为大根堆对左右子树之间元素的大小关系没有要求!)。
       2..那么如何利用此过程建立初始大根堆呢?
       若数组下标范围为0~n,考虑到单独一个元素是大根堆,则从下标[n/2]开始的元素均为大根堆(叶节点)于是只要从[n/2]-1开始,向前依次构造大根堆,这样就能保证,构造到某个节点时,它的左右子树都已经是大根堆(这就可以调用我们上面讨论的调整为大根堆的方法了)。一直到下标为0的结点,就完成了初始大根堆的建立。 堆排序用到的函数有两个:1个将左右子树都为大根堆的完全二叉树调整为大根堆的调整函数;1个反复调用此调整函数来进行排序的排序函数。

 

输入:50,435,6437,768,8,45,567,1435;
从第length/2开始构造,即第4个768开始构造大根堆

未命名