《算法导论》第六章 练习题 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 的堆,其高度与最大结点数的关系还是上式。

  

      

原文地址:https://www.cnblogs.com/Bw98blogs/p/8362026.html

时间: 2024-08-18 21:43:44

《算法导论》第六章 练习题 Exercise的相关文章

算法导论第六章 堆排序

堆的时间复杂度是建O(n),时间复杂度为堆排序O(NLogN),细节如以下的算法看到: #include <iostream> using namespace std; void swap(int &i,int &j) { int temp=i; i=j; j=temp; } void shiftDown(int *A, int start,int len) { int temp=A[start]; int i=start; int j=2*i+1; while (j<l

算法导论 第六章 思考题 6-1 用插入的方法建堆

BUILD-MAX-HEAP'(A) heap-size[A]<-1 for i <- 2 to length[A] do MAX-HEAP-INSERT(A, A[i]) 如上,题目给出一种使用插入的办法建堆的算法,而书中6.4节给出的建堆算法如下: BUILD-MAX-HEAP(A) heap-size[A] <-- length[A] for i <-- length[A] / 2 downto 1 do MAX-HEAPIFY[A, i] 可以发现元素调整的方向恰好反过来了

算法导论第六章优先队列(二)

优先队列可以说是堆的一个非常重要的应用,和堆对应,优先队列也分最小优先队列和最大优先队列. 优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中每一个元素都有一个关键字(key),关键字赋予了一个元素的优先级,故名为优先队列.之所以用堆来实现优先队列,我想最大的原因是堆很容易对元素按关键字进行排序. 优先队列的应用: 最大优先队列:其中最为典型的就是“共享计算机系统的作业调度”,通过记录各个作业的优先级,来调度一个作业的执行.删除和插入等操作. 最小优先队列:可以被用于“基于事件驱动的模

算法导论 第六章 思考题 6-3 d叉堆

d叉堆的实现相对于二叉堆变化不大,首先看它如何用数组表示. 考虑一个索引从1开始的数组,一个结点i最多可以有d个子结点,编号从id - (d - 2) 到 id + 1. 从而可以知道一个结点i的父结点计算方法为: (i + d - 2) / d. 第二个问题是 一个含有n个元素的d叉堆的高度,就是一个简单的等比数列的问题,可以知道的是一颗高度为h的满d叉树所含的结点数目为(d^(h +1) - 1) / (d - 1) 从而一颗含有 n个结点的d叉树满足的条件为: ,从而得到高度h为: 接下来

算法导论 第六章 思考题6-3 Young氏矩阵

这题利用二叉堆维持堆性质的办法来维持Young氏矩阵的性质,题目提示中写得很清楚,不过确实容易转不过弯来. a,b两问很简单.直接看c小问: 按照Young氏矩阵的性质,最小值肯定在左上角取得,问题在于取出最小值后如何保持矩阵的性质.可以参照max_heapify中的做法,先取出最小值,然后将矩阵左上角置为最大值,这样左上角处的元素必然导致Young氏矩阵的性质违背,于是考虑该元素右边的元素和该元素下边的元素,问题是该与右边元素交换还是与下边元素交换呢?可以发现,如果与T(右)和T(下)中较小的

算法导论第六章__实现优先队列

public class Priority_Queue { //储存的数组 private int A[]; //堆的大小 private int pile_Size=0; //如果找到指定值,返回 -1 private int NOT_FIND = -1; //堆容器的大小增量 private int INCREAT_CAPCITY=20; //堆容器大小 private static int INT_NUM=20; //构造函数1__不指定堆容器的大小,容器大小设置为默认大小,值:INT_N

算法导论第六章堆排序(一)

现在来看, 堆的含义大概有两种,一种是数据结构,一种是在一些语言中所定义的“垃圾回收机制”,如Java,在书本上的开篇强调了这两者,并强调若非特殊说明,皆把堆看做是一种数据结构. (二叉)堆的定义: 1)它是一个数组,可以被看成是一棵近似的完全二叉树,树上的每一个节点看做是数组中的每一个元素. 2)堆分为最大堆和最小堆,最大堆中每一棵子树的父节点的值大于孩子节点,最小堆则相反. 3)表示堆的数组A包括两个属性:A.length和A.heap_size.前者是数组元素的个数,后者是堆元素的个数,h

算法导论 第六章 堆排序

http://blog.csdn.net/mishifangxiangdefeng/article/details/7662515 http://www.cnblogs.com/Jiajun/archive/2013/05/31/3110256.html 这里练习6.3-3看http://blog.csdn.net/sailing_lqh/article/details/7381893的比较好理解

算法导论--第六章、堆排序

1. 堆的概念 堆的数据结构是一种数组对象:堆可以视作为一颗完全二叉树(其中,树的每一层都填满,最后一层可能除外):树中每个节点与数组中存放该节点值的元素对应: 堆可以划分为两类: a)     最大堆:除了根节点,有A[parent(i)] >= A[i],最大元素即根节点: b)     最小堆:除了根节点,有A[parent(i)] <= A[i],最小元素即根节点: 对于给定节点i,可以根据其在数组中的位置求出该节点的父亲节点PARENT(i)=i/2.左孩子LEFT(i) = 2*i