第6章 堆排序
2012-06-17 15:42
281 查看
一、概念
堆是一种数组对象,却被视频一棵完全二叉树
二、程序
三、练习
6.1
6.2
6.3
6.4
6.5
6.5-8算法导论6.5-8堆排序
四、思考题
6-1
a)A = [1,2,3];
6-2
a)
根结点是A[1],根结点的孩子是A[2]-A[d+1],……
PARENT(i) = (i - 2 ) / d + 1
CHILD(i, j ) = d * (i - 1) + j + 1
b)lgn/lgd
c)
d)和二叉堆的实现完全一样,时间复杂度是O(lgn/lgd)
e)和二叉堆的实现完全一样,时间复杂度是O(lgn/lgd)
6-3
a)不唯一
c)
d)
堆是一种数组对象,却被视频一棵完全二叉树
二、程序
#include <iostream> #include <stdio.h> using namespace std; #define PARENT(i) (i)>>1 #define LEFT(i) (i)<<1 #define RIGHT(i) ((i)<<1)+1 int length = 10;//数组中元素的个数 int heap_size = 10;//属于堆的元素个数,看到HeapSort就会明白 /******************其它************************************/ void Print(int *A) { int i; for(i = 1; i <= length; i++) { if(i > 1)cout<<','; else cout<<"==> A = {"; cout<<A[i]; } cout<<'}'<<endl;; } /*************************以下是堆处理函数****************************************/ //使以i结点为根结点的子树成为堆,调用条件是确定i的左右子树已经是堆,时间是O(lgn) //递归方法 void Max_Heapify(int *A, 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; //如果根最大,已经满足堆的条件,函数停止 //否则 if(largest != i) { //根与值最大的结点交互 swap(A[i], A[largest]); //交换可能破坏子树的堆,重新调整子树 Max_Heapify(A, largest); } } //非递归方法 void Max_Heapify2(int *A, 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; } } //建堆,时间是O(nlgn) void Build_Max_Heap(int *A) { heap_size = length; //从堆中最后一个元素开始,依次调整每个结点,使符合堆的性质 for(int i = length / 2; i >= 1; i--) Max_Heapify(A, i); } //堆排序,时间是O(nlgn) void HeapSort(int *A) { //建立一个最大堆 Build_Max_Heap(A); //每次将前i个元素构成最大堆 for(int i = length; i > 1; i--) { //将前i个元素中的最大值存入到A[i]中 swap(A[1], A[i]); //堆的大小减一 heap_size--; //只有堆顶的性质可能会被破坏 Max_Heapify(A, 1); } } /**********************以下是优先队列处理函数****************************************/ //将元素i的关键字增加到key,要求key>=A[i] void Heap_Increase_Key(int *A, int i, int key) { if(key < A[i]) { cout<<"new key is smaller than current key"<<endl; exit(0); } A[i] = key; //跟父比较,若A[PARENT(i)]<A[i],则交换 //若运行到某个结点时A[PARENT(i)]>A[i],就跳出循环 while([PARENT(i)] > 0 && A[PARENT(i)] < A[i]) { swap(A[PARENT(i)], A[i]); i = PARENT(i); } } //把key插入到集合A中 void Max_Heap_Insert(int *A, int key) { if(heap_size == 99) { cout<<"heap is full"<<endl; exit(0); } heap_size++;length++; A[heap_size] = -0x7fffffff; Heap_Increase_Key(A, heap_size, key); } //返回A中最大关键字,时间O(1) int Heap_Maximum(int *A) { return A[1]; } //去掉并返回A中最大关键字,时间O(lgn) int Heap_Extract_Max(int *A) { if(heap_size < 1) { cout<<"heap underflow"<<endl; exit(0); } //取出最大值 int max = A[1]; //将最后一个元素补到最大值的位置 A[1] = A[heap_size]; heap_size--; //重新调整根结点 Max_Heapify(A, 1); //返回最大值 return max; } //删除堆中第i个元素 void Heap_Delete(int *A, int i) { if(i > heap_size) { cout<<"there's no node i"<<endl; exit(0); } //把最后一个元素补到第i个元素的位置 int key = A[heap_size]; heap_size--; //如果新值比原A[i]大,则向上调整 if(key > A[i]) Heap_Increase_Key(A, i, key); else//否则,向下调整 { A[i] = key; Max_Heapify(A, i); } } int main() { cin>>length; heap_size = length; int A[100], i; for(i = 1; i <= length; i++) cin>>A[i]; Print(A); // Max_Heapify(A, 3); // Build_Max_Heap(A); // HeapSort(A); // Heap_Extract_Max(A); // Max_Heap_Insert(A, 10); return 0; }
三、练习
6.1
6.1-1 最多2^(h+1) - 1, 最少2 ^ h 6.1-2 根据上一题,2^h <= n <= 2^(h+1) - 1 ==> h <= lgn <= h + 1 ==> lgn = h 这两题中,当树只有一个结点时,高度是0 6.1-4 叶子上 6.1-5 是最小堆或最大堆 6.1-6 不是,7是6的左孩子,但7>6
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 Max_Heapify(int *A, 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.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中使用条件是当前结点的左孩子和右孩子都是堆
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-3 按递增排序的数组,运行时间是nlgn 按递减排序的数组,运行时间是n
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_Delete(int *A, 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(A, i, key); else { A[i] = key; Max_Heapify(A, i); } }
6.5-8算法导论6.5-8堆排序
四、思考题
6-1
a)A = [1,2,3];
6-2
a)
根结点是A[1],根结点的孩子是A[2]-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) 1 if heap-size[A] < 1 2 then error "heap underflow" 3 max <- A[1] 4 A[1] <- A[heap-size[A]] 5 heap-size[A] <- heap-size[A] - 1 6 MAX-HEAPIFY(A, 1) 7 return max MAX-HEAPIFY(A, i) 1 largest <- A[i] 2 for j = i to j+i+d-j 3 if j <= heap-size[A] and A[j] > A[i] 4 largest <- j 5 if largest != i 6 then exchange A[i] <-> A[largest] 7 MAX-HEAPIFY(A, largest)时间复杂度是O(lgn/lgd * d)
d)和二叉堆的实现完全一样,时间复杂度是O(lgn/lgd)
e)和二叉堆的实现完全一样,时间复杂度是O(lgn/lgd)
6-3
a)不唯一
2 | 3 | 4 | 5 |
8 | 9 | 12 | |
14 | 16 | ||
YOUNG-EXTRACR-MIN(Y) 1 if Y[1][1] == 0X7FFFFFFF 2 then error "heap underflow" 3 min <- Y[1][1] 4 A[1][1] <- 0X7FFFFFFF 5 MAX-HEAPIFY(Y, 1, 1) 6 return min MIN-YOUNGIFY(Y, i, j) 1 min <- Y[i][j] 2 if i < m and Y[i+1][j] < min 3 mini <- i+1 4 minj <- j 5 min <- Y[i+1][j] 6 if j < n and Y[i+1][j+1] < min 7 mini <- i 8 minj <- j+1 9 min <- Y[i][j+1] 10 if i != mini and j != minj 11 exchange Y[i][j] <-> Y[mini][minj] 12 MIN-YOUNGIFY(Y, mini, minj)
d)
MIN-YOUNG-INSERT(Y, key) 1 if Y[m] < 0x7fffffff 2 then error "young overflow" 3 Y[m] <- key 4 flag <- true 5 i <- m 6 j <- n 7 max <- key 8 while flag == true 9 if i > 1 and max < Y[i-1][j] 10 maxi <- i - 1 11 maxj <- j 12 max <- Y[i-1][j] 13 if j > 1 and max < Y[i][j-1] 14 maxi <- i 15 maxj <- j-1 16 max <- Y[i][j-1] 17 if max == key 18 flag = false 19 exchange Y[maxi][maxj] <-> Y[i][j] 20 i <- maxi 21 j <- maxjf)
FIND-YOUNG-KEY(Y, key) 1 i<- 1 2 j <- 1 3 while i <=m or j <= n 4 if key == Y[i][j] 5 then return true 6 if key < Y[i][j] 7 then return false 8 else 9 if i < m and Y[i+1][j] < key 10 i <- i + 1 11 else if j < n and Y[i][j+1] < key 12 j <- j + 1 13 else return false 14 return false
相关文章推荐
- 《算法导论》第6章 堆排序 (3)K路归并
- 《算法导论》第6章 堆排序 (4)Young氏矩阵
- 《算法导论》读书笔记之第6章 堆排序
- 《算法导论》第6章 堆排序 (3)K路归并
- 《算法导论》第6章 堆排序 (3)K路归并
- 第6章 论堆排序
- 算法导论 第6章 堆排序
- 《算法导论》第6章 堆排序 (3)K路归并
- 算法导论第6章实现堆排序的完整程序
- 第6章 堆排序,d叉堆,优先队列
- 算法导论 第6章 堆排序(简单选择排序、堆排序)
- 《算法导论》第6章 堆排序 个人笔记
- 算法学习导论学习笔记-第6章 堆排序
- 【算法导论 第6章 堆排序】
- 《算法导论》第6章 堆排序 (2)优先级队列
- 堆排序(第6章)
- 《算法导论》 - 第6章 - 堆排序 - 习题解答
- 《算法导论》第6章 堆排序 (2)优先级队列
- 【算法导论】学习笔记——第6章 堆排序
- 《算法导论》 - 第6章 - 堆排序 - 习题解答