二叉堆笔记c++

写在前面:

本篇有借鉴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;
}
//只需重载运算符

总结:

希望本篇文章对大家有所帮助,感谢观看!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值