6.5-1 试说明HEAP-EXTRACT-MAX在堆A={15,13,9,5,12,8,7,4,0,6,2,1}上的操作过程。
- <span style="font-size:14px;">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}上的操作过程。
- <span style="font-size:14px;">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的伪代码。
这里已经给出最小堆实现最小优先队列的代码。http://blog.csdn.net/z84616995z/article/details/17797393
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内循环部分的思想,只用一次赋值就完成一次交换操作?
- <span style="font-size:14px;">void HEAP_INCREASE_KEY(int A[],int i,int key)
- {
- if (key<A[i])
- {
- return ;
- }
- A[i]=key;
- while (i>0&&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操作。
- <span style="font-size:14px;">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具体解答。http://blog.csdn.net/z84616995z/article/details/17883173