1.堆
堆数据结构是一种数组对象,它可以被视为一科完全二叉树结构。它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆)。它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等。
2. 堆的基本操作
堆是一棵完全二叉树,高度为O(lg n),其基本操作至多与树的高度成正比。
Parent(t) t/2 表示父节点
Right(t) t*2 左孩子
Left(t) t*2+1 右孩子
HeapSize 堆的长度
详解参考:
http://www.cnblogs.com/Jason-Damon/archive/2012/04/18/2454649.html
http://blog.csdn.net/morewindows/article/details/6967409
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define maxn 100010 int a[maxn],n; void heapify(int a[],int n,int t)//调整根为t的树 { int left=t<<1; int right=t<<1|1; int max=t; if(left<=n)max=a[left]>a[max]?left:max; if(right<=n)max=a[right]>a[max]?right:max; if(max!=t)//当前根不是最大值 { swap(a[t],a[max]); //交换后子树可能会不满足最大堆的性质 heapify(a,n,max); } } void heapsort(int a[],int n) { //构建一个最大堆 for(int i=n/2;i>=1;i--)heapify(a,n,i); for(int i=n;i>1;i--) { //将最大值放在末尾 swap(a[i],a[1]); //交换后堆的容量减一,对堆重新调整(第一个节点的左右子树都是最大堆,所以只要对第一个节点进行调整) heapify(a,i-1,1); } } int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++)scanf("%d",&a[i]); heapsort(a,n); for(int i=1;i<=n;i++)printf("%d\n",a[i]); } return 0; }
tip:要得到从小到大的序列则构建最大堆,每次把最大值放在堆的末尾,要得到从大到小的序列则构建最小堆,每次把最小值放在末尾。
模板化的代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define Parent(t) t/2 #define Right(t) t<<1 #define Left(t) t<<1|1 int HeapSize; //数组A的数据是从1-n的 /* 保持堆的性质 Heapify(A,n,t) 该操作主要用于维持堆的基本性质。假定以RIGHT(t)和LEFT(t)为根的子树都已经是堆,然后调整以t为根的子树,使之成为堆。 */ class Rough { public: int x,y; double ratio; Rough(){} Rough(int _x,int _y,double _ratio) { x=_x; y=_y; ratio=_ratio; } bool operator >(const Rough& t) { return ratio-t.ratio>0.01; } bool operator <(const Rough& t) { return ratio<t.ratio; } bool operator ==(const Rough& t) { return ratio==t.ratio; } }; template<class T> void Heapify(T A[],int n,int t) { int left=Left(t); int right=Right(t); int max=t; if(left<=n)max=A[left]<A[max]?left:max; if(right<=n)max=A[right]<A[max]?right:max; if(max!=t) { T tmp=A[max]; A[max]=A[t]; A[t]=tmp; Heapify(A,n,max); } } /* 建堆 BuildHeap(A,n) 操作主要是将数组A转化成一个大顶堆。思想是,先找到堆的最后一个非叶子节点(即为第n/2个节点),然后从该节点开始,从后往前逐个调整每个子树,使之称为堆,最终整个数组便是一个堆。子数组A[(n/2)+1..n]中的元素都是树中的叶子,因此都可以看作是只含有一个元素的堆。 */ template<class T> void BuildHeap(T A[],int n) { for(int i=n/2;i>=1;i--) Heapify(A,n,i); } /* 堆排序算法 先用BuildHeapo将数组A[1..n]构造成一个最大堆。因为数组中最大元素在根A[1],则可以通过把它与A[n]交换来达到最终正确的位置。 */ template<class T> void HeapSort(T A[],int n) { BuildHeap(A,n); for(int i=n;i>1;i--) { T tmp=A[1]; A[1]=A[i]; A[i]=tmp; Heapify(A,i-1,1);//交换后堆的长度减1,对堆重新调整 } } int main() { //int a[6]={0,3,5,2,7,1}; Rough A[6]; A[1]=Rough(26,35,0.2); A[2]=Rough(522,1,5.5); A[3]=Rough(2132,2513,23); A[4]=Rough(1,2,3232); A[5]=Rough(-122,232,33); // BuildHeap(a,5); HeapSort(A,5); for(int i=1;i<=5;i++)printf("%d %d %lf\n",A[i].x,A[i].y,A[i].ratio); return 0; }
STL中优先队列的用法:
#include<cstdio> #include<queue> #include<iostream> using namespace std; struct node { int x,y; friend bool operator < (node a,node b) { return a.x<b.x; } }; //数据越小优先级越大 priority_queue<int,vector<int>,greater<int> >q; //数据越大优先级越大 priority_queue<int,vector<int>,less<int> >p; //默认是less int main() { int a[5]={6,9,3,5,7}; for(int i=0;i<5;i++)q.push(a[i]); while(!q.empty()) { printf("%d\n",q.top()); q.pop(); } for(int i=0;i<5;i++)p.push(a[i]); while(!p.empty()) { printf("%d\n",p.top()); p.pop(); } return 0; }