浅谈堆与并查集

堆与并查集在竞赛中很少直接涉及,但是我们可以利用这两种数据结构对算法进行优化。


定义

堆是一棵完全二叉树,且对于任意结点满足一定的父子关系。
用数组表示堆时,若有一个结点 A [ i ] A[ i ] A[i],那么它的父亲是 A [ ⌊ i 2 ⌋ ] A[ \lfloor \frac{i}{2} \rfloor ] A[2i]1,它的左儿子是 A [ 2 × i ] A[2\times i] A[2×i],它的右儿子是 A [ 2 × i + 1 ] A[2\times i + 1] A[2×i+1]
如果父结点永远小于等于儿子结点,那么这样的堆称作小根堆
如果父结点永远大于等于儿子结点,那么这样的堆称作大根堆


相关操作

堆有两种操作:

  1. 加入元素
  2. 取出堆顶

加入元素算法步骤:

  1. 在堆尾加入元素
  2. 比较它和它父结点的大小,如果不符合当前堆规定的父子关系,交换它的父结点,重复此步骤,直至它和它父结点符合当前堆的父子关系,或此元素已成为堆顶

代码如下(以小根堆做示范):

void putx(int x)
{
    
    
	int now,next;
	A[++size]=x;// 在堆尾加入元素
	now=size;
	while(now>1)// 重复此步骤,直至它和它父结点符合当前堆的父子关系,或此元素已成为堆顶
	{
    
    
		next=now/2;
		if(A[now] <= A[next]) break;// 比较它和它父结点的大小
		swap(A[now],A[next]);// 如果不符合当前堆的父子关系,交换它的父结点
		now=next;
	}
}

时间复杂度 O ( log ⁡ s i z e ) O(\log size ) O(logsize)

取出堆顶算法步骤:

  1. 取出堆顶元素
  2. 维护堆

代码如下(以小根堆做示范):

int popx()
{
    
    
	int now=1,next=0;
	int ret=A[1];
	A[1]=A[size};//将堆尾摆上堆顶
	size--;
	while(now*2<=size)
	{
    
    
		next=now*2;
		if(next<size&&A[next+1]<A[next]) next++;//如果可以到达右儿子下一个位置就去右儿子
		if(A[now]>=A[next]) break;//判断是否符合当前规定的父子关系
		swap(A[now,A[next]);
		now=next;
	}
	return ret;
}

时间复杂度 O ( log ⁡ s i z e ) O(\log size) O(logsize)


STL

在C++的STL中有大根堆即优先对列
需要的头文件

#include<queue>

定义的方式

priority_queue<数据类型> 变量名;

转成小根堆的两种方式

  1. 存入的元素的相反数
  2. 在尖括号中搞些事情(注意:最后两个尖括号之间要有空格,否则编译器会认为这是一个流的符号)
    priority_queue<数据类型 ,vector<数据类型 > ,greater<数据类型 > > 变量名;
    //                                                这个不能少 ↑ 
    

STL中提供的常用操作:
加入元素

heap.push(x);

获得堆顶元素

int x=heap.top();

删除堆顶

heap.pop();


并查集

定义

用于查询或合并 a , b a,b a,b两个元素所在的集合的数据结构
常用数组 f a t h e r [ i ] father[i] father[i]表示 i i i的父亲


相关操作

一共有四种操作:

  1. 初始化
  2. 寻找一个元素的根结点
  3. 合并两个集合
  4. 判断两个元素是否在同一集合

初始化

for(int i=1;i<=n;i++) father[i]=i;//i的根结点是它自己

寻找一个元素的根结点

int findx(int x)
{
    
    
	if(father[x]!=x) return findx(father[x]);
	return father[x];
}

合并两个集合

void unionx(int x,int y)
{
    
    
	x=findx(x);y=findx(y);
	father[y]=x;
}

判断两个元素是否在同一集合

bool judge(int x,int y)
{
    
    
	x=findx(x);y=findx(y);
	if(x==y) return 1;
	return 0;
}

  1. ⌊ x ⌋ \lfloor x \rfloor x x x x向下取整 ↩︎

猜你喜欢

转载自blog.csdn.net/bell041030/article/details/99757970