【堆的定义】
堆结构是具备以下性质的完全二叉树:
- 小根堆:每个结点的值都小于或等于其左右孩子结点的值
- 大根堆:每个结点的值都大于或等于其左右孩子结点的值
若将堆按照层序从 1 开始编号,则结点间满足下列关系:
- 小根堆:
- 大根堆:
从堆的定义可以看出,一个完全二叉树如果是堆,那么其根结点(堆顶)一定是当前堆中所有结点的最大值(大根堆)或最小值(小根堆),以层序结点编号为下标,将堆用顺序结构存储,那么堆对应于一组序列。
例如:
【堆的操作】
1.put 操作
put 操作,即向堆中加入一个元素,以大根堆为例,有:
- 在堆尾加入一个结点
- 将这个结点与其父结点进行比较:若其大于父结点,则将两者进行交换,否则操作结束
- 重复步骤 2,直到操作结束
int heap[N];
int size=0;
void put(int x){//heap[1]为堆顶
heap[++size]=x;//在堆尾加入元素
int now=size;//当前结点序号
while(now>1){
int next=now>>1;//该结点的父结点
if(heap[now]<=heap[next])//当前结点值小于其父结点值
break;
swap(heap[now],heap[next]);
now=next;
}
}
2.get操作
get 操作,即从堆中取出并删除堆顶元素,以小根堆为例,有:
- 令堆尾元素覆盖掉堆顶元素,并将其作为根结点 father,同时将堆的长度 -1
- 如果 father 有子结点,将根结点的子结点中最小的那个置为当前子结点的 son;若 father 没有子结点,结束操作
- 比较 father 与 son 的值,如果 father 的值小于或等于 son,结束操作;否则,交换这两个结点,并把 father 指向 son,重复步骤 2,直至操作结束
int heap[N];
int get(){//heap[1]为堆顶
int now=1;//当前结点
int res=heap[1];要删除的结点
heap[1]=heap[size--];//堆长度-1
while(now*2<=size){
int next=now>>1;//当前结点的父结点
if(next<size&&heap[next+1]<heap[next])//比较左右孩子,指向较大者
next++;
if(heap[now]<=heap[next])//当前结点值小于其父结点值,结束
break;
swap(heap[now],heap[next]);
now=next;
}
return res;
}