并查集的应用

408新增考点并查集,明确提到会考察并查集的应用,以下是两种主要应用的代码实现。
代码参考王道,侵删
基于邻接矩阵

判断无向图的连通分量数

//并查集的基本操作FIND
int Find(int s[],int x){
	while(s[x] >= 0)
		x = s[x];
	return x;
}

//并查集基本操作Union
void Union(int s[],int root1,int root2){
	if(root1 == root2) return;//在同一个集合中,无需合并
	//s[根节点]的绝对值标识以他为根的集合包含多少个结点
	//以负值代表
	if(s[root1] > s[root2]){//表明root1是小树,将小树挂到大树
		s[root2] += s[root1];//更新结点数
		s[root1] = root2;//root1指向root2
	}else{//root2是小树
		s[root1] += s[root2];
		s[root2] = s[root1];
	}
}

//此种算法下,FIND的时间复杂度为O(logn)
//Union的时间复杂度为O(1)

//计算无向图连通分量,以5x5的邻接矩阵为例
int ComponentCount(int g[5][5]){	
	int s[5];//A B C D E 五个结点
	for(int i=0;i<5;i++){
		s[i] = -1;
	}
	//因为是无向图,只用考虑上三角就行了
	for(int i=0;i<5;i++){
		for(int j=i+1;j<5;j++){
			if(g[i][j] > 0){//如果i,j之间有边,则并到一个集合
				int root1 = FIND(s,i);
				int root2 = FIND(s,j);
				Union(s,root1,root2)}
		}
	}
	//我们最后只需要统计有几个根,就知道有几个连通分量了
	int count;
	for(int i=0;i<5;i++){
		if(s[i] < 0)
			count++;
	}
	return count;
}

判断无向图中是否有环

void IsHaveCircle(int g[5][5]){
	int s[5];//创建一个并查集表
	for(int i=0;i<5;i++)
		s[i] = -1;

	for(int i=0;i<5;i++){
		for(int j=i+1;j<5;j++){
			if(g[i][j] > 0){
				int root1 = FIND(s,i);
				int root2 = FIND(s,j);
				//说明本身已经在集合中,又多了一条边。
				//这条边一定不是将他一开始加入集合的那条。
				//一开始,都不在并查集中,所以并一次之后,并不会再出现这条边
				if(root1 = root2){
					return 1;
				}else{//	不在同一个集合中,合并
					Union(s,root1,root2);
				}
			}
		}
	}
	return 0;//没有环
}

//时间复杂度O(n^2)

FIND优化。
即在FIND一次后,将其全部挂到自己的根结点下,下次再进行FIND操作,时间复杂度为O(1)

int FIND(int s[],int x){
	int root = x;
	while(s[root] >= 0)//找到根
		root = s[root];
	//再次遍历,将路径上的结点挂到根
	while(s[x] >=0){
		int parent = s[x];
		s[x] = root;//x直接挂到根结点上
		x = parent;
	}
	return root;
}

基于邻接矩阵实现

以下基于邻接矩阵实现上述两种应用
我对于c语言掌握不太好,可能有些许语法问题,见谅。

//数据结构定义
#define MaxVertexNum = 6
//边/弧
typedef struct ArcNode{
	int adjvex;
	struct ArcNode *next;//指向下一条弧的指针
	//InfoType info 可以添加一些边结点的其他信息
}ArcNode;

typedef VNode{
	VertexType data;//顶点信息
	ArcNode *first;//第一条边/弧
}VNode,AdjList[MaxVertexNum];
//用于存储邻接表的图
typedef struct{
	AdjList vertices;
	int vexnum,arcnum;//边数,结点数
}ALGraph

//计算连通分量数量
int ComponentCount(Graph *G){
	int vexnum = G.vexnum;
	int s[vexnum];
	for(int i=0;i<vexnum;i++){
		s[i] = -1;
	}
	for(int i=0;i< vexnum;i++){
		ArcNode p = G->vertices[i]->first;
		int data = G->vertices[i].data;
		while(p != null){
			int root1 = Find(s,data);
			int root2 = p.adjvex;
			Union(root1,root2);
		}
	}
	int count =0;
	for(int i=0;i<vexnum;i++){
		if(s[i] <=0)
			count++;
	}
	return count;
}

//确定有无环

int IsHaveCircle(Graph *G){
	int vexnum = G.vexnum;
	int s[vexnum];
	for(int i=0;i<vexnum;i++){
		s[i] = -1;
	}
	for(int i=0;i< vexnum;i++){
		ArcNode p = G->vertices[i]->first;
		int data = G->vertices[i].data;
		while(p != null){
			if(p.data > i){//因为是无向图,如果又遍历到序号比当前小的,之前一定已经加入过了【有问题,我之后再思考一下】
				int root1 = Find(s,data);
				int root2 = p.adjvex;
				if(root1 == root2)
					return 1;
				else
					Union(s,root1,root2);
			}
		}	
	}
	return 0}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值