写在前面:
本篇有借鉴oi.wiki,baidu
二叉堆(c++实现)_c++二叉堆_zhangshen12356的博客-CSDN博客
结构:
二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
存储:
二叉堆一般用数组来表示。如果根节点在数组中的位置是1,第n个位置的子节点分别在2n和 2n+1。因此,第1个位置的子节点在2和3,第2个位置的子节点在4和5。以此类推。这种基于1的数组存储方式便于寻找父节点和子节点。
Insert:
向二叉堆中插入一个带有权值val的新节点。我们把这个节点直接存储二叉堆的数组末尾,如何依据堆的性质不断向上调整。其复杂度O(logN).即堆的深度。这里以大根堆为例:
代码:
int head[SIZE];
void up(int x){
while(x>1){
while(head[x]>head[x/2]){//子节点大于父节点,不满足二叉堆性质
swap(head[x],head[x/2]);
x/=2;
}
else break;
}
}
void insert(int val){
head[++n]=val;
up(n);
}
GetTop:
GetTop操作返回堆顶权值,复杂度O(1)
int GetTop(){
return head[1];
}
Extract:
把堆顶从二叉堆中移除。
过程:
如果直接删除,则变成了两个堆,难以处理。
所以不妨考虑插入操作的逆过程,设法将根结点移到最后一个结点,然后直接删掉。
然而实际上不好做,我们通常采用的方法是,把根结点和最后一个结点直接交换。
于是直接删掉(在最后一个结点处的)根结点,但是新的根结点可能不满足堆性质……
向下调整:在该结点的儿子中,找一个最大的,与该结点交换,重复此过程直到底层。
可以证明,删除并向下调整后,没有其他结点不满足堆性质。——oi.wiki
注意:替换后仍为堆!
代码:
void down(int x){
int son=x*2;//x的左节点
while(son<=n){//保证子节点没有超过n
if(son<n && heap[son+1]>heap[son]) son++;//如果子节点不在最后一层,则取左节点与右节点更大的
if(heap[x]<heap[son]){//不满足大根堆性质
swap(heap[x],heap[son]);
x=son,son=x*2;//将父节点改为子节点,子节点改为父节点
}
else break;//满足直接退出
}
}
void Extract(){
heap[1]=heap[n--];
down(1);
}
Remove:
Remove(p)就是把堆中p删除,过程与Extract类似。但注意既需要向上调整也需要向下调整
代码:
void down(int x){
int son=x*2;//x的左节点
while(son<=n){//保证子节点没有超过n
if(son<n && heap[son+1]>heap[son]) son++;//如果子节点不在最后一层,则取左节点与右节点更大的
if(heap[x]<heap[son]){//不满足大根堆性质
swap(heap[x],heap[son]);
x=son,son=x*2;//将父节点改为子节点,子节点改为父节点
}
else break;//满足直接退出
}
}
void up(int x){
while(x>1){
if(heap[x]>heap[x/2]){
swap(heap[x],heap[x/2]);
p/=2;
}
else break;
}
}
void Remove(int k){
heap[k]=heap[n--];
up(k);
down(k);
}
C++STL的优先队列:
c++stl中的priority_queue(优先队列)为实现了一个大根堆,并支持push(Insert),top(GetTop)
pop(Extract),但不支持Remove。
STL 队列 (std::queue
) 是一种先进先出 (First In, First Out) 的容器适配器,仅支持查询或删除第一个加入的元素(队首元素),不支持随机访问,且为了保证数据的严格有序性,不支持迭代器。
头文件:#include <queue>
其调用函数:
top()
访问堆顶元素(此时优先队列不能为空)empty()
询问容器是否为空size()
查询容器中的元素数量push(x)
插入元素,并对底层容器排序pop()
删除堆顶元素(此时优先队列不能为空)
std::priority_queue<int> q1;
std::priority_queue<int, std::vector<int> > q2;
// C++11 后空格可省略
std::priority_queue<int, std::deque<int>, std::greater<int> > q3;
// q3 为小根堆
for (int i = 1; i <= 5; i++) q1.push(i);
// q1 中元素 : [1, 2, 3, 4, 5]
std::cout << q1.top() << std::endl;
// 输出结果 : 5
q1.pop();
// 堆中元素 : [1, 2, 3, 4]
std::cout << q1.size() << std::endl;
// 输出结果 :4
for (int i = 1; i <= 5; i++) q3.push(i);
// q3 中元素 : [1, 2, 3, 4, 5]
std::cout << q3.top() << std::endl;
// 输出结果 : 1
实现小根堆:
//priority_queue实现小根堆
struct res{
int id;double value;
};
bool operator<(const rec &a,const rec &b){
return a.value>b.value;
}
//只需重载运算符
总结:
希望本篇文章对大家有所帮助,感谢观看!