《算法导论》第六章 练习题 Exercise

Posted 大峰子的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法导论》第六章 练习题 Exercise相关的知识,希望对你有一定的参考价值。

6.1-1


 

  在高度为 h 的堆中,元素最多有 2h+1 - 1 个,最少有 2h  个。注意算法导论里的高度是指深度,从 0 开始而不是从 1 开始。

 

6.1-2


 

  这很好想,但是不好证明。

  由已知高度为 h 的堆,它的元素个数满足 2h   <= n <= 2h+1 - 1 ,解出 lg(n+1) - 1 <= h <= lgn ,但是它不够“合理”,因为当 n = 2h+1-1 时,n 等于 2的幂 - 1,此时 lg(n+1) -1 = ⌊lgn⌋ ,所以 ⌊lgn⌋ <= h <= lgn 。而我们默认高度 h 是一个自然数,所以左右界一致,得出 h = ⌊lgn⌋ 。

 

6.1-3


 

  最大堆的属性告诉我们除了根结点以外的所有结点都要满足 A[PARENT(I)] >= A[I] ,一棵树是递归定义的,所以子树的最大结点肯定是其根结点。

 

6.1-4


 

  它一定是叶子结点,位于 ⌊lgn⌋ 或 ⌊lgn⌋ - 1 层

 

6.1-5


 

  按递增排序的话,是的

 

6.1-6


 

  不是,"PARENT" 6 < "CHILD" 7

 

6.1-7


 

  通过反证法比较好证明。

  假设 i ∈ { ⌊n/2⌋+1, ⌊n/2⌋+2, ... , n } ,那么它的孩子的序号至少是 2·(⌊n/2⌋+1), 2·(⌊n/2⌋+2) ,显然不在数组内。

  所以可以得到结论:堆中叶子结点数 = ⌈n+1⌉

 

6.2-1


 

   3 先与左右儿子比较,找到其中最大的关键字并记录它的索引,让它与 3 交换,递归调用实现 3 的子树堆化。

 

6.2-2


 

  维护最小堆的算法如下:

#define LEFT(i) (2*i + 1)
#define RIGHT(i) (2*i + 2)

MIN-HEAPIFY (A, i)
    left = LEFT (i)
    right = RIGHT (i)
    if left <= A.HEAPSIZE && A[left] < A[i]
        min_index = left
    else
        min_index = i
    if right <= A.HEAPSIZE && A[right] < A[min_index]
        min_index = right
    if min_index != i
        exchange A[i] and A[min_index]
        MIN-HEAPIFY(A, min_index)

  时间一样,都是 Θ(lgn)

 

6.2-3


 

  不会进行递归堆化。  

 

6.2-4


 

  其子结点的序号超出了堆的大小,程序将视为其子结点不存在,所以不会进行堆化操作。

 

6.2-5


 

  尾递归改循环控制结构如下:  

#define LEFT(i) (2*i + 1)
#define RIGHT(i) (2*i + 2)

MAX-HEAPIFY (A, i)
    while i < A.HEAPSIZE
        left = LEFT(i)
        right = RIGHT(i)

        if left < A.HEAPSIZE && A[left] > A[i]
            max_index = left
        else
            max_index = i

        if right < A.HEAPSIZE && A[right] > A[max_index]
            max_index = right

        if max_index != i 
            exchange A[max_index] and A[i]
        else
            return;

 

6.2-6


 

  ...

 

6.3-1


 

  从 ⌊A.length/2⌋ 开始,即第一个非叶子结点 10 开始(最大)堆化,然后是 3、2、1 。过程很简单,直接写结果了,得到的数组是 {84, 22, 19, 10, 3, 17, 6, 5, 9}

 

6.3-2


 

  我们从 ⌊n/2⌋ 开始的目的是要让每次迭代前后 i 都是最大堆的根。如果从 1 开始,那么将无法保持最大堆的特性(无法保证循环不变式)。

 

6.3-3

  这里将利用到 6.1-7 的结论:堆中叶子结点数 = ⌈n/2⌉

  首先,当 h = 0 时(算法导论中高度深度都是从 0 开始),高度为零的堆就是叶子结点组成的堆,有  ⌈n/2⌉ 个这样的堆,结点数是 ⌈n/2⌉

  假设当 h = h-1 时,结论成立。

  有一颗高度为 h 的堆,如果把它的叶子结点都剪去后它将变成高度为 h - 1 、结点数为 n - ⌈n/2⌉ = ⌊n/2⌋ 的堆,代入 h = h-1 时的结论,有如下推导:

  

  同理,我们可以用高度为 h+1 的堆剪去叶子结点得到高度为 h 的堆,其高度与最大结点数的关系还是上式。

 

  

      

以上是关于《算法导论》第六章 练习题 Exercise的主要内容,如果未能解决你的问题,请参考以下文章

算法导论笔记——第六七章 堆排序和快速排序

数据结构与算法(周鹏-未出版)-第六章 树-习题

补基础:自学:计算机科学导论 第六章 计算机网络

网络空间安全导论第一章第二章第六章第七章第一节第九章脑图

Python核心编程(第二版)第六章部分习题代码

计网第六章