算法导论第六章6.5优先队列课后答案。

6.5-1 试说明HEAP-EXTRACT-MAX在堆A={15,13,9,5,12,8,7,4,0,6,2,1}上的操作过程。

HEAP-EXTRACT-MAX(A)
if(A.heap-size<1)        //堆中元素是否为空
  error"heap underflow"  //如果是空的,那么返回错误
max=A[1]                 //将最大堆最大元素也就是第一个元素保存起来
A[1]=A[A.heap_size]      //将堆中最后一个元素赋值给第一个元素
A.heap_size=A.heap_size-1//堆元素数量减少1
MAX-HEAPIFY(A,1)//保持最大堆的性质
return max//返回这个最大元素

堆A个元素的顺序是: A={1,13,9,5,12,8,7,4,0,6,2}
                    A={13,1,9,5,12,8,7,4,0,6,2}
                    A={13,12,9,5,1,8,7,4,0,6,2}
                    A={13,12,9,5,6,8,7,4,0,1,2}


6.5-2/6.5-4试说明MAX-HEAP-INSERT(A,10)在堆A={15,13,9,5,12,8,7,4,0,6,2,1}上的操作过程。

MAX-HEAP-INSERT(A,key)
A.heap-size=A.heap-size+1          //将堆中元素个数+1
A[A.heap-size]=负无穷大            //因为堆中新的最后一个元素开始没有被赋值,所以是一个不确定的数,而
//这个不确定的数可能大于待插入的key,这样就不符合原书本意。而被赋值为负无穷大后,保证了key>A[A.heap-size]
HEAP-INCREASE-KEY(A,A.heap-size,key)//在key>A[A.heap-size]前提条件满足的情况下,增加A[A.heap-size]值到key实现插入

堆A个元素的顺序是: A={15,13,9,5,12,8,7,4,0,6,2,1,负无穷大}
                    A={15,13,9,5,12,8,7,4,0,6,2,1,10}
                    A={15,13,9,5,12,10,7,4,0,6,2,1,8}
                    A={15,13,10,5,12,9,7,4,0,6,2,1,8}


6.5-3 要求用最小堆实现最小优先队列,请写出HEAP-MINMUM,HEAP-EXTRACT-MIN,HEAP-DECREASE-KEY和MIN-HEAP-INSERT的伪代码。

这里已经给出最小堆实现最小优先队列的代码。


6.5-5试分析在使用下列循环不变量时,HEAP-INCREASE-KEY的正确性:
     在算法的第4-6行while循环每次迭代开始的时候,子数组A[1..A.heap-size]要满足最大堆的性质。如果有违背,那么只有一种可能,A[i]>A[PARENT(i)].这里,你可以假定在调用HEAP-INCREASE-KEY时,A[1..A.heap-size]是满足最大堆性质的。


初始:在循环开始前,除了刚增加的A[i]=key不满足最大堆性质,其他元素都满足最大堆性质。
保持:在循环过程中,通过不断交换key值与其parent值,并且不断更新parent值来使增加元素值得堆满足最大堆性质。
终止:当i=1或A[PARENT(i)]>=A[i]时,代表所有元素已经排好,并且满足最大堆,那么循环自然终止。


6.5-6 在HEAP-INCREASE-KEY的第5行的交换操作中,一半需要通过三次赋值来完成。想一想如何利用INSERTION-SORT内循环部分的思想,只用一次赋值就完成一次交换操作?

void HEAP_INCREASE_KEY(int A[],int i,int key)
{
    if (key0&&A[PARENT(i)]<=key)
    {
        //swap(A[i],A[PARENT(i)]);
        A[i]=A[PARENT(i)];//利用插入排序内部循环思想
        i=PARENT(i);
    }
    A[i]=key;
}

6.5-7 试说明如何使用优先队列来实现一个先进先出队列,以及如何使用优先队列来实现栈。(队列和栈的定义见10.1节)


设置最大堆第一个元素为队头Q.head,最后一个元素为队尾Q.tail。


先进先出队列的插入:当队列中有元素要入队,我们可以调用最大堆插入函数,先检测Q.tail==Q.head+1?测试栈是否满?然后把队尾Q.tail向后移动一位,再把队尾Q.tail=负无穷大,再调用HEAP-INCREASE-KEY函数实现插入。


先进先出队列的删除:先检测Q.tail==Q.head?测试栈是否空?调用HEAP-INCREASE-KEY(A,i,A[1])函数把待删除的元素增加到最大值,调用HEAP-EXTRACT-MAX(A)来删除,最后队尾Q.tail往前移动一位。


这就是先进先出的队列插入删除操作,这里不谈其他操作。


设置最大堆第一个元素为队头S.bottom,最后一个元素为队尾S.top。


先进后出栈的插入:当栈中要有新元素加入时,我们可以调用最大堆插入函数,先检测S.top>n? 然后把S.top向上移动一位,并设置新的S.top=负无穷大,调用HEAP-INCREASE-KEY函数,最后调用BUILD-MAX-HEAP(A)保持最大堆性质。实现插入。


先进先出栈的删除:先检测S.top=0?然后将该元素A[i]与栈顶元素A[heap-size]交换,S.top向下移动一位,最后调用BUILD-MAX-HEAP(A)保持最大堆性质。实现删除。


这就是先进后出的栈的插入删除操作,这里不谈其他操作。

6.5-8 HEAP-DELETE(A,i)操作能够将结点i从堆A中删除。对于一个包含n个元素的堆,请设计一个能够在O(lgn)时间内完成的HEAP-DELETE操作。


HEAP-DELETE(A,i)
HEAP-INCREASE-KEY(A,i,A[1])//将待删除的元素增加到数组最大值也就是最大堆第一个元素的值
HEAP-EXTRACT-MAX(A)//数组中有2个最大值,利用此函数删除一个实现对A[i]的删除。

6.5-9 请设计一个时间复杂度为O(nlgk)的算法,它能够将k个有序链表合并为一个有序链表,这里n是所有输入链表包含的总的元素个数。(提示:使用最小堆来完成k路归并)


这里是6.5-9具体解答。

你可能感兴趣的:(《算法导论》)