算法导论第六章总结:堆排序

算法导论第六章总结:堆排序

       这一章介绍了另一种排序算法:堆排序。它的时间复杂度为 O(n lg n),且具有空间原址性(即任何时候只需要常数个额外的元素空间存储临时数据)。时间复杂度优于插入排序,与归并排序相同。且具有归并排序不具备的空间原址性这一优点。并且,这一章引入了“堆”这种数据结构。

       

一、堆 P84、85

      (二叉)堆是一个数组,它可以被看成是一个近似的完全二叉树。树上的每一个结点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且是从左向右填充。表示堆的数组 A 包括两个属性:A.length 给出数组元素的个数,A. heap-size 表示有多少个堆元素存储在该数组中。

         给定一个结点的下标 i,我们可计算出它的父节点、左孩子和右孩子的下标:

         PARENT(i)           LEFT(i)          RiGHT(i)

         return└ i/2 ┘        return 2i          return2i+1

        二叉堆可分为两种形式:最大堆和最小堆。其中最大堆是指对除根结点外的所有结点 满足:A[ PARENT(i) ] ≥ A[i]。最小堆则是 A[ PARENT(i) ] ≤ A[i]。之后我们的算法均默认为最大堆。

        接下来介绍一些基本过程,其中n代表元素个数。

        MAX-HEAPIFY:其时间复杂度为 O(lgn),用来维护最大堆性质,也就是使堆满足A[ PARENT(i) ] ≥ A[i]。

        BUILD-MAX-HEAP:具有线性复杂度,从无序的输入数据数组中构造一个最大堆。

        HEAPSORT:其时间复杂度为 O(n lg n),对一个数组进行原址排序。

        MAX-HEAP-INSERT、HEAP-EXTRACT-MAX、HEAP-INCREASE-KEY和HEAP-MAXIMUM:时间复杂度O(lgn),功能是从利用堆来实现一个优先队列。


二、维护堆的性质(最大堆)P85~87

         MAX-HEAPIFY 用于维护最大堆的性质。它的输入为一个数组 和一个下标 i它使以 A[i] 为根节点的树满足最大堆性质,但前提是假定根结点为 LEFT(i) 和 RIGHT(i) 的二叉树都是最大堆。MAX-HEAPIFY 通过让 A[i] 在最大堆中“逐级下降”,从而使得以下标i为根结点的子树重新遵循最大堆的性质。

         

  MAX-HEAPIFY( A, i )

        l=LEFT (i)

        r=RIGHT (i)

  if l ≤ A. heap-size and A[l]> A[i]

            largest = l

   else largest = i

  if r ≤A. heap-size and A[r]> A[largest]

            largest = r

  if largest ≠ i

            exchange A[i] with A[largest]

        MAX-HEAPIFY( A, largest )



        上述递归式的解为T(n)=O( lgn)。


三、建堆 P87~P89

        我们用 MAX-HEAPIFY 把一个大小为n =A.length 的数组 A[ 1…n ] 转换为最大堆。因为子数组的元素是树的叶结点,所以对其他结点调用 MAX-HEAPIFY 即可。

        

        BUILD-MAX-HEAP (A)

        A. heap-size = A. length

        for i =  downto 1

        MAX-HEAPIFY (A , i)

                         


图1    时间复杂度分析(没太看懂。。。)



图2    BUILD-MAX-HEAP操作过程示意图


四、堆排序算法 P89、90    

        堆排序算法就是已知一个最大堆,并把该最大堆按照从大到小的顺序排成数组。对于此算法,通俗地讲,就是先把根结点元素取出,放进数组中作为最大值,原因是最大堆中根结点元素一定最大,我们通过将 A[1] 和 A[n] 互换并减少 A. heap-sizeA. heap-size =A. heap-size- 1)来实现。将 A[n] 换上去之后,不再满足最大堆性质(但高度h - 1以下仍满足最大堆性质),所以我们调用 MAX-HEAPIFY ( A , 1 ),让换上去的元素找到自己合适的位置,使整个堆(A[1]~A[n-1])重新满足最大堆的性质。不断重复这一过程,直到最后一个元素。
          

     HEAPSORT(A)

      BUILD-MAX-HEAP(A)

for i = A. lengthdownto 2

             exchange A[1] with A[i]

             A. heap-size = A. heap-size - 1

             MAX-HEAPIFY (A , 1)

        HEAPSORT 过程的时间复杂度是 O(n lg n),因为调用 BUILD-MAX-HEAP 的时间复杂度是 O(n) ,而 n-1 次调用 MAX-HEAPIFY,每次的时间为 O(lg n)。



图3   HEAPSORT 过程操作过程示意图


五、优先队列 P90~P92

         这一节介绍了堆的一个常见应用:优先队列。这里,我们关注如何基于最大堆来实现最大优先队列。
        普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (largest-in,first-out)的行为特征。其中每个元素都有一个相关的值,称为关键字( key )。

         一个最大优先队列支持以下操作:

         INSERT(S,x ): 把元素x插入到集合S中。

         MAXIMUM(S ): 返回S中具有最大关键字的元素。

         EXTRACT_MAX(S ): 去掉并返回S中具有最大关键字的元素。

         INCREASE_KEY( S, x, k ): 将元素x的关键字值增加到k,这里假设k的值不小于x的原关键字值。

         优先队列可以用堆来实现。在用堆的来实现优先队列时,需要在堆中的每个元素里存储对应对象的句柄。关于句柄,其含义依赖于具体程序,但我的理解就是一种标识,比如指针、数组下标,可通过句柄访问对象。接下来,我们讨论如何实现最大优先队列的操作。


          HEAP-MAXIMUM(A)

         returnA[1]


         HEAP-EXTRACT-MAX(A)

         1    if A. heap-size < 1

         2       error “heap underflow”

         3    max = A[1]

         4    A[1] = A[A.heap.size]

         5    A. heap-size = A. heap-size - 1

         6    MAX-HEAPIFY (A , 1)

         7    returnmax

         理论上讲,HEAP-EXTRACT-MAX 只需要返回 A[1] 即可,4~6行是为了维护最大堆性质,保证提取 max 之后仍为最大堆。


        HEAP-INCREASE-KEY (A, i, key)

        if key < A[i]

            error “new key is smaller than current key”

        A[i] = key

        while i > 1 and A[parent(i)]< A[i]

                  exchange A[i] with A[parent(i)]

                  i = PARENT(i)

        算法第3行做了关键字更新的结点到根结点的路径长度为 O(lg n) ,所以时间复杂度为 O(lg n) 。该算法增大 A[i] 的关键字到 key,并重新选择 A[i] 的位置,使整个堆满足最大堆的性质。


          MAX-HEAP-INSERT (A, key)

        A. heap-size = A. heap-size - 1

        A[A. heap-size] =-∞

        HEAP-INCREASE-KEY (A, A. heap-size,key)

        该算法的输入时要被插入到最大堆 中的新元素的关键字。首先扩展最大堆,然后调用 HEAP-INCREASE-KEY 为新结点设置对应的关键字,同时保持最大堆的性质。时间复杂度为 O(lg n)。

        总之,包含 个元素的堆中,所有优先队列的操作都可以在 O(lg n) 时间内完成。










      

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值