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;
}