篇首:
二叉堆是非常非常简单的数据结构,是入门级别的基础,但是我知道算法思想,没有去实践过(一般用到堆时直接STL的priority_queue),最近在刷刷基础且李总让我们总结算法,于是心血来潮手打一波二叉堆。(重要的事情说三遍:priority_queue是大根堆性质、priority_queue是大根堆性质、priority_queue是大根堆性质)
理解:
二叉堆首先是一颗二叉树,然后满足堆的性质。若子节点小于等于父节点,则称该二叉树为大根堆,同理若子节点大于等于父节点,则称该二叉树为小根堆。
二叉堆操作的实现(以大根堆为例):
插入:
直接将需要插入的数x放在heap末尾,然后向上调整,直到满足大根堆性质结束。
求max值:
由于维护的是大根堆,所以直接返回堆首heap[1]
删去堆首:
直接将堆首与heap末尾节点交换,并使节点个数减1,然后由新的根节点不断向下调整,直到满足大根堆性质为止(注意每次调整应该和左右儿子中的较大值交换,显然so不解释)。
删去某个下标的值:
方法类似于删去堆首,将所需删除下标x的heap[x]与末尾节点交换,节点个数减1,然后要么向上调整要么向下调整(显然so不解释)
完整代码:
1 #include<bits/stdc++.h> 2 #define il inline 3 #define ll long long 4 #define debug printf("%d %s\n",__LINE__,__FUNCTION__) 5 using namespace std; 6 const int N=500005; 7 int n,x,heap[N],cnt; 8 il int gi() 9 { 10 int a=0;char x=getchar();bool f=0; 11 while((x<‘0‘||x>‘9‘)&&x!=‘-‘)x=getchar(); 12 if(x==‘-‘)x=getchar(),f=1; 13 while(x>=‘0‘&&x<=‘9‘)a=a*10+x-48,x=getchar(); 14 return f?-a:a; 15 } 16 il void up(int x) //上调 17 { 18 while(x>1){ 19 if(heap[x]>heap[x>>1]){swap(heap[x],heap[x>>1]);x>>=1;} 20 else break; 21 } 22 } 23 il void insert(int x){heap[++cnt]=x;up(cnt);} //插入 24 25 il int gettop(){return cnt?heap[1]:-1;} //取出堆顶,即最大值 26 27 il void down(int x) 28 { 29 int s=x<<1; //x左儿子 30 while(s<=cnt){ 31 if(s<cnt&&heap[s]<heap[s+1])s++; //取左右儿子的较大值 32 if(heap[s]>heap[x]){swap(heap[s],heap[x]);x=s,s=x<<1;} //维护大根堆父节点大于子节点的性质 33 } 34 } 35 il void extrat(){heap[1]=heap[cnt--];down(1);} //删除堆顶 36 37 il void remove(int x){heap[x]=heap[cnt--];up(x),down(x);} //删除下标位置为x的节点 38 int main() 39 { 40 n=gi(); 41 while(n--){ 42 int a=gi(); 43 if(a==1)x=gi(),insert(x); 44 if(a==2)printf("%d\n",gettop()); 45 if(a==3)extrat(); 46 if(a==4)x=gi(),remove(x); 47 } 48 return 0; 49 }