您的位置:首页 > 其它

算法导论 第6章 堆排序

2012-06-17 15:42 387 查看

一、概念

1.定义

(1)堆heap

堆是一种数组对象The (binary) heap data structure is an array object that can be viewed as a nearly complete binary tree

(2)最大堆max-heap

for every node i other than the root,A[PARENT( i)] ≥ A[i]

(3)最小堆min-heap

for every node i other than the root,A[PARENT( i)] ≤ A[i]

(4) height

Viewing a heap as a tree, we define the height of a node in a heap to be the number of edges on the longest simple downward path from the node to a leaf, and we define the height of the heap to be the height of its root

2.性质

(1)堆可以被视频一棵完全二叉树,二叉树的层次遍历结果与数组元素的顺序对应,树根为A[1]。对于数组中第i个元素,具体计算如下
PARENT(i)
    return i/2
LEFT(i)
    return 2i
RIGHT(i)
    return 2i+1


二、程序

1.堆的结构

A
:堆数组
length[A]:数组中元素的个数
heap-size[A]:存放在A中的堆的元素个数

2.在堆上的操作

(1)MAX-HEAPIFY(A, i)(2)BUILD-MAX-HEAP(A)(3)HEAPSORT(A)

3.堆的应用

优先级队列(1)HEAP-MAXIMUM(A)(2)HEAP-INCREASE-KEY(A, i, key)(3)HEAP-EXTRACT-KEY(A)(4)MAX-HEAP-INSERT(A, key)

4.堆代码

产品代码测试代码

5.排序代码

产品代码
测试代码 可以使用git工具下载、更新、提交、评论代码

三、练习

6.1 堆

6.1-1
最多2^(h+1) - 1, 最少2 ^ h(当树中只有一个结点时,高度是0)
6.1-2
根据上一题,2^h <= n <= 2^(h+1) - 1
 ==> h <= lgn <= h + 1
 ==> lgn = h
6.1-3
根据定义(1)
max-heap的定义
==>A[PARENT(i)]>=A[i]
==>A[1]>A[2],A[3]
==>A[1]>A[4],A[5],A[6],A[7]
==>……
==>the root of the subt ree contains the largest value
6.1-4
叶子上
6.1-5
是最小堆或最大堆
6.1-6
不是,7是6的左孩子,但7>6
6.1-7
根据性质(1)
A[2i]、A[2i+1]是A[i]的孩子
==>若2i<=n&&2i+1<=n,则A[i]有孩子
==>若2i>n,则A[i]是叶子
==>the leaves are the nodes indexed by ?n/2 ? + 1, ?n/2 ? + 2, . . . , n


6.2 保持堆的性质

6.2-1
    A = {27,17,3,16,13,10,1,5,7,12,4,8,9,0}
==> A = {27,17,10,16,13,3,1,5,7,12,4,8,9,0}
==> A = {27,17,10,16,13,9,1,5,7,12,4,8,3,0}
6.2-2
MIN-HEAPIFY(A, i)
 1    l <- LEFT(i)
 2    r <- RIGHT(i)
 3    if l <= heap-size[A] and A[l] < A[i]
 4        then smallest <- l
 5        else smallest <- i
 6    if r <= heap-size[A] and A[r] < [smallest]
 7        then smallest <- r
 8    if smallest != i
 9        then exchange A[i] <-> A[smallest]
10                MIN_HEAPIFY(A, smallest)
6.2-3
没有效果,程序终止
6.2-4
i > heap-size[A]/2时,是叶子结点,也没有效果,程序终止
6.2-5 我还是比较喜欢用C++,不喜欢用伪代码
void Heap::Max_Heapify(int i)
{
	int l = (LEFT(i)), r = (RIGHT(i)), largest;
	//选择i、i的左、i的右三个结点中值最大的结点
	if(l <= heap_size && A[l] > A[i])
		largest = l;
	else largest = i;
	if(r <= heap_size && A[r] > A[largest])
		largest = r;
	//如果根最大,已经满足堆的条件,函数停止
	//否则
	while(largest != i)
	{
		//根与值最大的结点交互
		swap(A[i], A[largest]);
		//交换可能破坏子树的堆,重新调整子树
		i = largest;
		l = (LEFT(i)), r = (RIGHT(i));
		//选择i、i的左、i的右三个结点中值最大的结点
		if(l <= heap_size && A[l] > A[i])
			largest = l;
		else largest = i;
		if(r <= heap_size && A[r] > A[largest])
			largest = r;
	}
}
6.2-6
MAX-HEAPIFY中每循环一次,当前处理的结点的高度就会+1,最坏情况下,结点是根结点的时候停止,此时结点高度是logn,因此最坏运行时间是logn



6.3 建堆

6.3-1
A = {5,3,17,10,84,19,6,22,9}
==> A = {5,3,17,22,84,19,6,10,9}
==> A = {5,3,19,22,84,17,6,10,9}
==> A = {5,84,19,22,3,17,6,10,9}
==> A = {84,5,19,22,3,17,6,10,9}
==> A = {84,22,19,5,3,17,6,10,9}
==> A = {84,22,19,10,3,17,6,5,9}
6.3-2
因为MAX-HEAPIFY中使用条件是当前结点的左孩子和右孩子都是堆
假设对i执行MAX-HEAPIFY操作,当i=j时循环停止,结果是从i到j的这条路径上的点满足最大堆的性质,但是PARENT[i]不一定满足。甚至有可能在满足A[PARENT(i)]>A[i]的情况下因为执行了MAX-HEAPIFY(i)而导致A[PARENT(i)]<A[i],例如下图,因此一定要先执行MAX-HEAPIFY(i)才能执行MAX-HEAPIFY(PARENT(i))



6.3-3见http://blog.csdn.net/lqh604/article/details/7381893

6.4 堆排序的算法

6.4-1
    A = {5,13,2,25,7,17,20,8,4}
==> A = {25,13,20,8,7,17,2,5,4}
==> A = {4,13,20,8,7,17,2,5,25}
==> A = {20,13,17,8,7,4,2,5,25}
==> A = {5,13,17,8,7,4,2,20,25}
==> A = {17,13,5,8,7,4,2,20,25}
==> A = {2,13,5,8,7,4,17,20,25}
==> A = {13,8,5,2,7,4,17,20,25}
==> A = {4,8,5,2,7,13,17,20,25}
==> A = {8,7,5,2,4,13,17,20,25}
==> A = {4,7,5,2,8,13,17,20,25}
==> A = {7,4,5,2,8,13,17,20,25}
==> A = {2,4,5,7,8,13,17,20,25}
==> A = {5,4,2,7,8,13,17,20,25}
==> A = {2,4,5,7,8,13,17,20,25}
==> A = {4,2,5,7,8,13,17,20,25}
==> A = {2,4,5,7,8,13,17,20,25}
==> A = {2,4,5,7,8,13,17,20,25}
6.4-2
不知道题目是什么意思,是证明题?
6.4-3
按递增排序的数组,运行时间是nlgn
按递减排序的数组,运行时间是n
6.4-4
堆排序算法中,对堆中每个结点的处理过程为:
(1)取下头结点,O(1)
(2)把最后一个结点移到根结点位置,O(1)
(3)对该结点执行MAX-HEAPIFY,最坏时间为O(lgn)
对每个结点处理的最坏时间是O(lgn),每个结点最多处理一次。
因此最坏运行时间是O(nlgn)

6.4-5求高人解答,点击打开链接

6.5 优先级队列

6.5-1
    A = {15,13,9,5,12,8,7,4,0,6,2,1}
==> A = {1,13,9,5,12,8,7,4,0,6,2,1}
==> A = {13,1,9,5,12,8,7,4,0,6,2,1}
==> A = {13,12,9,5,1,8,7,4,0,6,2,1}
==> A = {13,12,9,5,6,8,7,4,0,1,2,1}
return 15
6.5-2
    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,-2147483647}
==> 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-MINIMUM(A)
1    return A[1]
HEAP-EXTRACR-MIN(A)
1    if heap-size[A] < 1
2        then error "heap underflow"
3    min <- A[1]
4    A[1] <- A[heap-size[A]]
5    heap-size[A] <- heap-size[A] - 1
6    MIN-HEAPIFY(A, 1)
7    return min
HEAP-DECREASE-KEY(A, i, key)
1    if key > A[i]
2        then error "new key is smaller than current key"
3    A[i] <- key
4    while i > 1 and A[PARENT(i)] > A[i]
5        do exchange A[i] <-> A[PARENT(i)]
6              i <- PARENT(i)
MIN-HEAP-INSERT
1    heap-size[A] <- heap-size[A] + 1
2    A[heap-size[A]] <- 0x7fffffff
3    HEAP-INCREASE-KEY(A, heap-size[A], key)
6.5-4
要想插入成功,key必须大于这个初值。key可能是任意数,因此初值必须是无限小
6.5-6
FIFO:以进入队列的时间作为权值建立最小堆
栈:以进入栈的时间作为权值建立最大堆
6.5-7
void Heap::Heap_Delete(int i)
{
	if(i > heap_size)
	{
		cout<<"there's no node i"<<endl;
		exit(0);
	}
	int key = A[heap_size];
	heap_size--;
	if(key > A[i])   //最后一个结点不一定比中间的结点最
		Heap_Increase_Key(i, key);
	else
	{
		A[i] = key;
		Max_Heapify(i);
	}
}

6.5-8见算法导论6.5-8堆排序-K路合并

四、思考题

6-1 用插入方法建堆

void Heap::Build_Max_Heap()
{
	heap_size = 1;
	//从堆中最后一个元素开始,依次调整每个结点,使符合堆的性质
	for(int i = 2; i <= length; i++)
		Max_Heap_Insert(A[i]);
}
答:
a)A = {1,2,3};
b)MAX-HEAP-INSERT的过程如下:
加入大小为-0x7FFFFFFF的新结点,O(1)
将该值调整为key,最坏情况下为O(lgn)
对每个结点都要执行一次插入操作,因此最坏时间为O(nlgn)


6-2 对d叉堆的分析

a)根结点是A[1],根结点的孩子是A[2],A[3],……,A[d+1]
PARENT(i) = (i - 2 ) / d + 1  
CHILD(i, j ) = d * (i - 1) + j + 1  
b)lgn/lgd  
c)HEAP-EXTRACR-MAX(A)与二叉堆的实现相同,其调用的MAX-HEAPIFY(A, i)要做部分更改,时间复杂度是O(lgn/lgd * d)  
MAX-HEAPIFY(A, i)
1    largest <- A[i]  
2    for j <- 1 to d
3        k <- CHILD(i, j)  
4        if k <= heap-size[A] and A[j] > A[largest]  
5            largest <- k
6    if largest != i  
7    then exchange A[i] <-> A[largest]  
8             MAX-HEAPIFY(A, largest)  
d)和二叉堆的实现完全一样,时间复杂度是O(lgn/lgd)  
e)和二叉堆的实现完全一样,时间复杂度是O(lgn/lgd)


6-3 Young氏矩阵

算法导论 6-3 Young氏矩阵
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: