代码如下
不太理解的地方可以先看注释,注释看不懂可以留言或者私信我,如果有写错的地方欢迎大家指出谢谢!!
#include <stdio.h>
#define MAX 5
//采用邻接矩阵存储的无向图(此图有2连通图,并且存在环)
int g[MAX][MAX]={0,3,1,0,0,
3,0,4,0,0,
1,4,0,0,0,
0,0,0,0,2,
0,0,0,2,0
};
/**
* 并查集查找根节点
* @param A 并查集
* @param x 待查找根节点的节点
* @return
*/
int find(int A[],int x){
int root = x;
while (A[root]>=0) root = A[root];//依次向上找到根节点
//把寻找路径上的节点全部设置为根节点,方便下次寻找
while (x!=root){
int t = A[x];
A[x] = root;
x = t;
}
return root;
}
/**
* 并查集的合并操作,根节点的绝对值表示当前根节点下一共有多少节点,每次合并小树往大树合并
* @param A 并查集
* @param Root1 待合并的根1
* @param Root2 待合并的根2
* @return
*/
bool Union(int A[],int Root1,int Root2){
if(Root1==Root2) return false;//Root1和Root2相等则不需要合并
//判断谁是大树谁是小树
if(A[Root2]>A[Root1]) {
A[Root1] += A[Root2];//小树的根节点数加到大树上
A[Root2] = Root1;//小树的根节点设置为大树的根节点
} else{
A[Root2] += A[Root1];
A[Root1] = Root2;
}
}
/**
* 初始化并查集,根节点全部初始为-1
* @param A 并查集
*/
void init(int A[]){
for (int i = 0; i < MAX; ++i) {
A[i] = -1;
}
}
/**
* 并查集的应用,查找连通图的数量
* @param G 采用邻接矩阵存储的无向图
* @return 返回连通图的数量
*/
int ComponentCount(int G[MAX][MAX]){
int S[MAX];
int count;
init(S);
//把连通的节点加入同一个集合中,不连通的节点则不处于同一个集合中
for (int i = 0; i < MAX; ++i)
//因为是无向图,所以只用遍历上三角区域
for (int j = i+1; j < MAX; ++j)
//说明i到j有边
if(G[i][j]>0){
int iRoot = find(S,i);//找到i的根节点
int jRoot = find(S,j);//找到j的根节点
if(iRoot != jRoot)//判断是否处于同一个并查集中
Union(S,iRoot,jRoot);//不在同一个并查集则合并
}
//遍历一次并查集,小于0的节点说明为根节点,有几个根节点说明有几个集合,即连通图的数量
for (int i = 0; i < MAX; ++i) {
if(S[i]<0) count++;
}
return count;
}
/**
* 判断图中是否存在环
* @param G 采用邻接矩阵存储的无向图
* @return 有环返回true,没有环返回false
*/
bool hasAcyclic(int G[MAX][MAX]){
int S[MAX];
init(S);
//把连通的节点加入同一个集合中,不连通的节点则不处于同一个集合中
for (int i = 0; i < MAX; ++i)
//因为是无向图,所以只用遍历上三角区域
for (int j = i+1; j < MAX; ++j)
if(G[i][j]>0){
int iRoot = find(S,i);//找到i的根节点
int jRoot = find(S,j);//找到j的根节点
if(iRoot != jRoot)//判断是否处于同一个并查集中
Union(S,iRoot,jRoot);//不在同一个并查集则合并
else return true;//在同一个并查集则说明之前已经加入过,属于同一个集合,此时又出现一个联通边,说明存在环,直接返回true
}
return false;//遍历完成没有发现环,返回false
}
int main() {
printf("%d\n", ComponentCount(g));
if(hasAcyclic(g))
printf("hasAcyclic\n");
else printf("noAcyclic\n");
return 0;
}