6-1-1: 解: 最少的情况为第h层只有一个叶子节点,那么元素数为2h,最多的情况为该树是一颗完全二叉树,元素数为2h+1-1
6-1-2: 解:根据上一题我们可以知道,对于有n个元素的堆,必须满足如下式子: 2h <= n <=2h+1-1 < 2h+1,所以又h <= lgn < h+1,故h = └lgn┘
6-1-3: 解:假设该最大元素A不在根上,那么我们知道在这颗子树中,除了跟节点,其余节点都有父节点,那么A就要比父节点的数值大,与该树是最大堆相 盾,故最大元素A在子树的根上
6-1-4: 解:最小元素只可能在叶子节点上
6-1-5: 解:是最小堆,满足最小堆的性质
6-1-6: 解:不是,元素为6的节点,它的右子节点为元素7,
6-1-7: 解:另第一个叶子节点为i,则有 (i-1)*2 +1 <= n,i*2> n,所以很容易得知得一个叶子节点为 i = └n/2┘+1
6-2-1: 解: 略(不好写)
6-2-2: 解: MIN-HEAPIFT(A,i)
l <- Left(i)
r <- Right(i)
if l <= heap-size(A) and A[i] > A[l]
then smallest <- l
else smallest <- i
if r <= heap-size(A) and A[smallest] > A[r]
then smallest <- r
if smallest != i
exchange A[i] and A[smallest]
MIN-HEAPIFY(A,smallest);
时间复杂度为O(lgn)
6-2-3: 解:不进行任何处理,直接返回
6-2-4: 解:不进行任何处理,直接返回
6-2-5: 解:MAX-HEAPIFT(A,i)
while (true)
l <- Left(i)
r <- Right(i)
if l <= heap-size(A) and A[i] < A[l]
then largest <- l
else largest <- i
if r <= heap-size(A) and A[smallest] < A[r]
then largest <- r
if largest != i
then exchange A[i] and A[largest]
i <- largest
else break;
6-2-6: 解:当输入数组是一个排序好了的递增数组时,共需要调用lgn次MAX-HEAPIFY,每次调用都是O(1)时间,所以整个算法最坏运行时间为O(lgn)
6-3-1: 解:略
6-3-2: 解:因为调用MAX-HEAPIFY子程序的时候必须要保证它的左右子树是最大堆性质,而从1开始的话,显然它的左右子树不是最大堆性质的子树
6-3-3: 解:略
6-4-1: 解: 25 13 20 8 7 17 2 5 4 20 13 17 8 7 4 2 5 25 17 13 5 8 7 4 2 20 25
13 8 5 2 7 4 17 20 25 8 7 5 2 4 13 17 20 25 7 4 5 2 8 13 17 20 25
5 4 2 7 8 13 17 20 25 4 2 5 7 8 13 17 20 25 2 4 5 7 8 13 17 20 25
6-4-2: 解:初始: 初始态的时候i=n,故很显然循环不变式是正确的
保持: 因为迭代每一次都是将前i个元素中最大的一个放到了前i个元素序列的末尾,而这个最大元素根据前面的迭代过程很显然是小于后面i+1.....n 个元素的,故保持了这一性质
终止: 终止时i=1,表明后面2.....n个元素是排好序的,且都大于第一个元素,故整个序列是排好序的
6-4-3: 解:O(nlgn)和Ω(nlgn)
6-4-4: 解:当输入的数组是不同时,Build-Heap时间复杂度为O(n),每一次调换元素都破换了原有最大堆的性质,故为Ω(nlgn)
6-5-1: 解:为 13 12 9 5 6 8 7 4 0 1 2 15
6-5-2: 解:为 15 13 10 5 12 9 7 4 0 6 2 1 8
6-5-2: 解:HEAP_MIN(A)
return A[1]
HEAP_EXTRACT_MIN(A)
min<-A[1]
A[1] <- A[heap-size(A)]
heap-size(A) <- heap-size(A)-1
MIN_HEAPIFY(A,1)
HEAP_DECREASE_KEY(A,i,key)
if A[i] < key
then return error
A[i] <- key
while i>1 and A[parent(i)]>A[i]
exchange A[i] and A[parent[i]]
i<- parent(i)
6-5-4: 解:因为HEAP_INCREASE_KEY会比较key和A[i]的大小,如果key要小于A[i]就直接返回了
6-5-5: 解:初始:即A[i]的值增加到key,则整个最大堆就在节点i发生了增大,很明显,循环不变式是对的
保持:当迭代的过程中,发生了交换,那么狠明显,节点i的子树肯定保持了最大堆性质,而整个树唯一有可能不满足最大堆的性质的只可能发生在 i=paranet(i)节点上。循环不变式也成立
终止:如果数在i>1的情况下终止的话,那么数肯定是一个最大堆数,而如果在i<1的情况下终止,因为此时已经到达根节点了,而在根节点下面仍 然保持了最大堆性质
6-5-7: 解:思路:想增大节点i的值,让它上移到根节点,然后删除根节点,
6-5-8: 解:思路:建立一个大小为k的数组,然后将k个链表的第一个元素压入数组,构建最小堆(O(lgk)),然后取出最小元素min,然后将min->nodeNext压入数组,构建最小堆,重复操作
6-1: 解:a、不一样,如当输入数组为 8 5 3 9 2 4 6 7,BUILD_MAX_HEAP为: 9 8 6 7 2 4 3 5,而INSERT为:9 8 6 7 2 3 4 5
b、对于每次插入为logn,共n次插入,故为O(nlogn)
6-2: 解:a、节点i的父节点为:(i-2)/d+1向上取整,第一个子节点为(i-1)d+2,一次类推到第d个子节点
b、树的高度为logdn向下取整
c、max = A[1]
A[1] <- max[heap-size(A)]
heap-size(A) = heap-size(A)-1
Max-Heapify(A,1)
运行时间为O(dlogdn)
d、heap-size(A) <- heap-size(A)+1
A[heap-size(A)] = -∞
Heap-Increase-key(A,heap-size(A),key);
运行时间为O(logdn);
e、 if key <A[i] then return
A[i] = key
while i>1 and A[parent(i)] < A[i]
exchange A[i] and A[parent(i)]
i <- parent(i);
运行时间为O(logdn);
6-3: 解: a、 2 3 4 5
8 9 12 14
16 ∞ ∞ ∞
∞ ∞ ∞ ∞
b、因为Y[1,1] = ∞,那么对于m*n矩阵,第一行和第一列的所有元素必然为∞(因为是排好序的),对于对于矩阵中的任意一个元素Y(i,j),如果该 元素不为空,那么它左边和上边的元素必然不为空,即Y(1,j)和Y(i,1)不为空,相矛盾,故得证,同理可得正第二个命题
c、可以利用类似于max_heapify的递归思想,将最小元素A[1,1]取出后再用∞赋值A[1,1],然后对交换后的矩阵左上角元素进行递归操作 reverse_young_min_heapify,直到整个矩阵符合Young氏矩阵的规则。T(p) = T(p-1) + O(1),解递归式易得:T(p) = O(m+n)。
d、也是利用堆的思想,先将A[m,n]赋值为待插入元素,然后进行堆化递归操作即可。
e、利用extract_min易证。
f、思路是从矩阵右上角开始,如果该元素==k,则找到;如果该元素<k,则删去最上行,重复操作;如果该元素>k,则删去最右行,重复操作
如有错误,或是更好的解答方法,望路过的牛人指出,谢谢