算法导论6-5

读书笔记

本小节讲述了堆排序在实际中的应用--优先队列,优先队列可以在共享计算机操作系统进行作业调度。

最大优先队列支持如下操作:

插入

将元素\(x\)根据它的优先级插入到合适的位置;

实现过程

在最大堆的最末端插入一个无穷小的叶子节点,然后为这个节点赋值,然后使用递归调整该节点到合适位置;

伪代码

MAX-HEAP-INSERT(A, key)
A.heap-size = A.heap-size + 1
A[A.heap-size] = -∞
HEAP-INCREASE-KEY(A, A.heap-size, key)

\(HEAP-INCREASE-KEY\)的伪代码在下方。

获取最大值

获取当前最大堆中的最大值;

实现过程

最大堆的根节点天然就是最大值;

伪代码

HEAP-MAXIMUM(A)
return A[1]

弹出最大值

获取当前最大队的最大值,并且从堆中去除该值;

实现过程

弹出最大值,然后将最尾子节点作为根节点,调整当前堆到最大堆;

伪代码

HEAP-EXTRACT-MAX(A)
if A.heap-szie < 1
 	error "heap underflow"
max = A[1]
A[1] = A[A.heap-size]
A.heap-size = A.heap-size -1
MAX-HEAPIFY(A, 1)
return max

提高优先级

对于已经提高了优先级的元素,调整到合适的位置;

实现过程

通过和父节点的不断比较,提高优先级,调整位置;

伪代码

HEAP-INCREASE-KEY(A,i,key)
	if key < A[i]
		error "new key is smallar than current key"
A[i] = key
while i > 1 and A[PARENT(i)] < A[i]
	exchange A[i] with A[PARENT(i)]
	i = PARENT(i)

课后习题

前三题难度不高但是比较费事,所以省略

6.5-4

\(MAX-HEAP-INSERT\)中,为什么我们要先把关键字设为\(-\infty\),然后又将其增加到所需要的值呢?

为了方便调用\(HEAP-INCREASE-KEY\)

6.5-5

试分析在使用下列循环不变量时,\(HEAP-INCREASE-KEY\)的正确性:

在算法的第4~6行while循环每次迭代开始的时候,子数组\(A[1..A.heap-size]\)要满足最大堆的性质。如果有违背,只有一个可能:\(A[i]\)大于\(A[PARENT(i)]\)

6.5-6

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

HEAP-INCREASE-KEY(A,i,key)
	if key < A[i]
		error "new key is smallar than current key"
while i > 1 and A[PARENT(i)] < key
	A[i] = A[PARENT(i)]
	i = PARENT(i)
A[i] = key

6.5-7

试说明如何使用优先队列实现一个先进先出的队列,如何使用优先队列来实现栈?

队列:此处的优先级为任务添加到队列的时间,越小优先级越高;

:此处的优先级为任务添加到队列的时间,越大优先级越高;

6.5-8

\(HEAP-DELETE(A,i)\)操作能将节点\(i\)从堆\(A\)删除。对于一个包含\(n\)个元素的堆,请设计一个能够在\(O(\lg{n})\)时间内完成的\(HEAP-DELETE\)操作。

其实这个过程和\(HEAP-EXTRACT-MAX\)是相似的,只是这里的根节点为\(A[i]\)

6.5-9

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

假设\(k=2\),那么条件就变为设计一个时间复杂度为\(O(n)\)的算法将2个有序链表合并为一个有序链表;

通过最小堆不断选出最小值来完成排序。

posted @ 2021-01-15 10:38  ijkzen  阅读(112)  评论(0编辑  收藏  举报