算法导论第六章-堆排序
2014-10-26 09:31
337 查看
一、概念
1.定义
(1)堆heap
堆的本质是个数组,但是可以看成一个近似的完全二叉树。
(2)最大堆max-heap
根结点的值大于等于子结点的值,根结点(堆顶)的值始终是最大的。
(3)最小堆min-heap
跟结点的值小于等于子结点的值
(4) height
根结点到叶结点最长简单路径上边的数目。
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),维护最大堆的性质,时间复杂度为O(lgn)。(2)BUILD-MAX-HEAP(A),从无序数组中构造最大堆,时间复杂度为O(n)。
(3)HEAPSORT(A),堆排序,时间复杂度为O(nlgn)。
3.堆的应用
利用堆实现一个最大优先级队列,最大优先队列的实质就是无论进行什么操作,始终维护最大堆的性质,堆顶始终保持最大,优先级最高(1)HEAP-MAXIMUM(A),返回堆中的最大元素,时间复杂度为O(1)。
(2)HEAP-INCREASE-KEY(A, i, key),用key代替下标为i的元素,O(lgn)。
(3)HEAP-EXTRACT-KEY(A),去掉堆顶并返回,还要维护堆的性质,O(lgn)。
(4)MAX-HEAP-INSERT(A, key),插入元素,并维护堆的性质,O(lgn)。
(5) HEAP-DELETE(A,i),删除下标为i的元素,并维护堆的性质,O(lgn)。
代码:
//头文件 #include <iostream> #include <stdio.h> using namespace std; //宏定义 #define N 1000 #define PARENT(i) (i)>>1<span style="white-space:pre"> </span> #define LEFT(i) (i)<<1 #define RIGHT(i) ((i)<<1)+1 class Heap { public: //成员变量 int A[N+1]; int length; int heap_size; //构造与析构 Heap(){} Heap(int size):length(size),heap_size(size){} ~Heap(){} //功能函数 void Max_Heapify(int i); void Build_Max_Heap(); void HeapSort(); //优先队列函数 void Heap_Increase_Key(int i, int key); void Max_Heap_Insert(int key); int Heap_Maximum(); int Heap_Extract_Max(); void Heap_Delete(int i); //辅助函数 void Print(); }; //使以i结点为根结点的子树成为最大堆,调用条件是确定i的左右子树已经是堆,时间是O(lgn) //递归方法 void Heap::Max_Heapify(int i) { Print(); 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(largest); } } //建堆,时间是O(nlgn) void Heap::Build_Max_Heap() { heap_size = length; //从堆中中间元素开始,依次调整每个结点,使其符合堆的性质,因为堆的后半段数组都是树的叶子结点,每个叶结点可以看成只包含一个元素的堆,因此可以从length/2开始调用<span style="font-family: Arial;">Max_Heapify去建立一个堆</span> for(int i = length / 2; i >= 1; i--) Max_Heapify(i); } //堆排序,从小到大,每次把堆顶(最大)与最后一个元素交换,这个最大的值即确定,然后对前面的堆维护最大堆的性质,循环即可。时间是O(nlgn) void Heap::HeapSort() { //使无序数组成为最大堆 Build_Max_Heap(); for(int i = length; i > 1; i--) { //将最大的元素即堆顶放到最后 swap(A[1], A[i]); //堆的大小减一,然后再对前heap_size-1个元素维护堆的性质 heap_size--; //堆顶由于刚才的swap破坏了性质,调用<span style="font-family: Arial;">Max_Heapify使其重新变成最大堆</span> Max_Heapify(1); } } //将元素i的关键字增加到key,要求key>=A[i] void Heap::Heap_Increase_Key(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(A[PARENT(i)] > 0 && A[PARENT(i)] < A[i]) { swap(A[PARENT(i)], A[i]); i = PARENT(i); } } //把key插入到集合A中 void Heap::Max_Heap_Insert(int key) { if(heap_size == N) { cout<<"heap is full"<<endl; exit(0); } heap_size++;length++; A[heap_size] = -0x7fffffff; Heap_Increase_Key(heap_size, key); } //返回A中最大关键字,时间O(1) int Heap::Heap_Maximum() { return A[1]; } //去掉并返回A中最大关键字,时间O(lgn) int Heap::Heap_Extract_Max() { if(heap_size < 1) { cout<<"heap underflow"<<endl; exit(0); } //取出最大值 int max = A[1]; //将最后一个元素补到最大值的位置 A[1] = A[heap_size]; heap_size--; //重新调整根结点 Max_Heapify(1); //返回最大值 return max; } //删除堆中第i个元素 void Heap::Heap_Delete(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(i, key); else//否则,向下调整 { A[i] = key; Max_Heapify(i); } } void Heap::Print() { int i; for(i = 1; i <= length; i++) { if(i > 1)cout<<','; else cout<<"==> A = {"; cout<<A[i]; } cout<<'}'<<endl; }
相关文章推荐
- 算法导论第六章 堆排序C++源码(附图)
- 《算法导论》第六章 堆排序 笔记
- 《算法导论》第六章“堆排序”习题解答
- 算法导论_第六章_堆排序
- 算法导论第六章 堆排序C++源码(附图)
- 算法导论(第三版)第六章 堆排序的全部实现(堆排序,优先队列)
- 算法导论 第六章 堆排序
- 算法导论 第六章 堆排序
- 算法导论第六章 堆排序
- 算法导论学习笔记-第六章-堆排序
- 算法导论第六章:堆排序
- 《算法导论》第六章-堆排序(伪代码)
- 《算法导论》第六章----堆排序练习(证明)(完整版)
- 算法导论详解(5) 第六章 堆排序
- 算法导论第六章 堆排序
- 算法导论习题--第六章[堆排序]
- 算法导论第六章伪码转C++ ___堆排序
- 《算法导论》学习笔记--第六章 堆排序
- 算法导论 第六章 堆排序 习题6.5-8 k路合并排序
- 学习《算法导论》第六章 堆排序 总结