A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© xqlyn123 中级黑马   /  2015-10-28 11:25  /  669 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

一:什么是堆?
1.堆: n个元素的序列{k1,k2,k3,.....kn}当且仅当满足以下关系是,称为堆. {ki <= k2i 且 ki <= k2i+1} 或
{k2i <= ki 且 k2i+1 <= ki} (i = 1,2,...[n/2] ).这也是堆的一个性质.

2.堆结构是一种数组对象堆,它可以被视为一棵完全二叉树如下图,  书中每个节点与数组中存放该节点中值的那个元素
对应,除了最后一层,其余的每个节点都是满的.因为堆可看成是一棵完全二叉树,那它就满足一些树的性质,
对于有n个结点的完全二叉树,对任一结点i 有:  
  1)如果 i = 1,则结点i是二叉树的根,无双亲;
    2)如果i > 1,则其双亲Parent(i)是[ i / 2];
    3)如果2i > n,则结点i 无左孩子(结点i为叶子结点);否则,其左孩子Lift_child(i) 是结点2i.
    4)如果2i + 1 > n,则结点i无右孩子;否则,其右孩子right_child(i)是结点2i + 1.
    5)其非终端结点是第[ n / 2]个元素,(非终端结点是指:完全二叉树中的最后一个带有叶子的结点).
         
  

二:堆的分类
堆包含: 1.大根堆. 2.小根堆.      
        1. 大根堆必须满足: {ki <= k2i , ki <= k2i+1}  (i = 1,2,...[n/2] ), 大根堆排序后元素是由小到大的顺序.
        2.小根堆必须满足:  {k2i <= ki , k2i+1 <= ki} (i = 1,2,...[n/2] ).  小根堆排序后元素是由大到小的顺序.
【例】关键字序列(10,15,56,25,30,70)和(70,56,30,25,15,10)分别满足堆性质(1)和(2),
故它们均是堆,其对应的完全二叉树分别如小根堆示例和大根堆示例所示:



在下面所举的例子或代码中默认的是数组中元素是从下标1开始存储的.

三:如何实现堆排序?
1.堆排序需要解决的两个问题就是:(1)如何由一个无序序列建成一个堆? (2)如何在输出堆顶元素之后,
   调整剩余元素成为一个新的堆?
      
2. 让一个无序序列建成一个堆的最重要的步骤就是堆调整(牢记堆性质).
    堆调整的思想:
       1).把待调整的记录当成根,然后 比较此根和其左,右孩子这三个数的大小,如果左,右孩子中还中有一个最大的,
            则把此最大值与根值交换(这是大根堆调整法,小根堆调整只需找到最小的值并与根交换就行),
       2).接着从最大值下标开始,并又以此结点为根重复1)中的步骤直到最大值下标循环的叶子结点.
        3)如果1)中比较后得到的最大值(/最小值)仍为根,则表示以此根结点的子序列已满足堆性质,就已经是堆了,

下面就堆调整的伪代码:
    array[]可知是我们将要调整的序列数组,index 则表示的是将要调整的记录的下标.wait_adjust_length是待调整堆的长度.  
点击(此处)折叠或打开

  • heap_adjust(NumType array[], int index ,int wait_adust_length)
  •     lift_index = 2 * index ;//记录待调整记录的左孩子的下标
  •     right_index = 2 * index + 1;//记录待调整记录的右孩子的下标
  •   if lift_index <= wait_adjust_lenght and array[lift_index] > array[right_index]
  •           then max_num_index = lift_index;
  •           else max_num_index = right_index;
  •   if right_index <= wait_adjust_length and array[right_index] > array[max_num_index]
  •    then max_num_index = right_index;
  •    if max_num_index != index
  •         then exchange array[index] <---> array[max_num_index]
  •           heap_adjust(array, max_num_index);


heap_adjust的作用过程如下图:  此处wait_adjust_length = 10;
        图a) 改堆的初始构造,在节点i =2处array[2]违反了堆的性质,因为它不大于它的两个子女(此处是以 大根堆 举例).  
在图b)中通过交换array[2]与array[4],因此在结点2处恢复的堆的性质,但又在结点4处违反了堆的性质现在递归调用heap_adjust(array, 4)就置index=4.
图(c)中在交换了array[4]与array[9]后,结点,结点4处堆性质得到恢复,递归调用heap_adjust(array, 9)对该数据结构不再引起任何变化.        
    在算法的每一步里,从元素array,array[lift_index]和array[right_index]中找到最大的,并将其下标存在max_num_index中.如果array[index]是最大的,则以index为根的子树已是堆,算法结束.否则,
index的某个子结点中有最大元素,则换array[index]和array[max_num_index],从而使i及其子女
满足堆的性质,交换后的结点max_num_index中原先的array[index],以该结点为根的子树又有可能
违反堆性质,因而,要对该子树递归调用heap_adjust.

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马