学习笔记:堆

前言

堆是在大纲里面的 但是大家都在有 priority_queue 优先队列 以至于很少人去学习手写堆
因此 需要补一补

概念

什么是堆?

就是一棵完全二叉树任意当前节点必定比儿子大/小 这就是大/小根堆
性质:堆的子树也是堆

步骤

1.查找最小值

很简单 返回堆顶即可

2.插入一个数

为了不破坏完全二叉树的性质 选择在叶子节点加一个数 这样会破坏堆的性质
怎么办?
维护以下就行
暴力把这个点往上旋转 知道满足堆性质就行了!

void Pushup(int x)
{
	while(x>1)
	{
		if(val[x]<val[x/2])swap(val[x],val[x/2]);
		else break;
		x/=2;
	}
	return ;
} 
void insert(int x)
{
	val[++tot]=x;
	Pushup(tot);
}

很简单

3.删除堆顶

这个难搞 可不想把一棵树分裂成两棵
不妨这样想 把根节点丢到堆底 删掉堆底就行了
但这样子会使得根破坏性质
怎么办?
考虑下转
考虑维护小根堆
若当前节点比两个儿子节点大 那就把当前节点和小的那个点转一下就行
转到满足即可
注意判断边界

void insert(int x)
{
	val[++tot]=x;
	Pushup(tot);
}
void Pushdown(int x)
{
	while(x*2<=tot)
	{
		int son=x*2;
		if(son+1<=tot&&val[son+1]<=val[son]) son++;
		if(val[x]>val[son])swap(val[son],val[x]);
		else break;
		x=son;
	}
}

所有操作都结束了 十分简单!
现在分析时间复杂度
首先 因为保证是 完全二叉树 因此树高不超过\(O(\log n)\)
因此 查询是 \(O(1)\)
删除,增加复杂度是 \(O(\log n)\)
因此 总时间复杂度为 \(O(n\log n)\)

posted @ 2023-08-28 16:06  g1ove  阅读(4)  评论(0编辑  收藏  举报