数据结构算法—邻接表存储的无向图求连通分量个数

数据结构算法—邻接表存储的无向图求连通分量个数

邻接表存储结构

typedef struct ArcNode{
	int adjvex;//边指向的顶点
	struct ArcNode *nextarc; // 下一条边的指针 
}ArcNode;
typedef struct VNode{
	int data;//顶点信息 
	ArcNode *fristarc;//该结点的第一条边 
}VNode,AdjList[MAX];
typedef struct {
	AdjList vertices;//头结点数组
	int vexnum,arcnum; // 图的当前顶点数和边数 
}ALGraph;

求连通分量算法思想:

无向图的连通分量: 在离散数学中,几个顶点连在一起,不和其他的顶点互通有无。即构成一个连通分量。 单个顶点也是一个连通分量。
在数据结构中,使用图的遍历算法,从某一个顶点出发,一直寻找与他邻接的顶点。访问过得顶点就标记出来(使用vis[] 数组)。直到 没有邻接的顶点 或者 所有的顶点都访问过了。每结束一次深度遍历就 count(连通分量个数) 加 1 。

tips:

顶点的信息保存在Adjlist 数组中,,输入的顶点值 和 数组中保存的索引值 可能会不同,要统一使用 索引值 所以我写了一个 LocateVex 函数 ,用来寻找 顶点值 对应的 索引值 ,并返回索引值!

完整代码
#include
#include
#define MAX 100
int vis[100];
typedef struct ArcNode{
	int adjvex;//边指向的顶点
	struct ArcNode *nextarc; // 下一条边的指针 
}ArcNode;
typedef struct VNode{
	int data;//顶点信息 
	ArcNode *fristarc;//该结点的第一条边 
}VNode,AdjList[MAX];
typedef struct {
	AdjList vertices;//头结点数组
	int vexnum,arcnum; // 图的当前顶点数和边数 
}ALGraph;
//寻找v1,v2在G中的位置
int LocateVex(ALGraph *G,int v){
	int i;
	for(i=0;i<=G->vexnum;i++)
		if(G->vertices[i].data==v)
			return i;
} 
//创建图
void creatGraph(ALGraph *G){
	int i,j,k,m,n;
	ArcNode *s;
	printf("请输入图的顶点数和边数:");
	scanf("%d%d",&G->vexnum,&G->arcnum);
	getchar();//吃掉回车
	printf("请依次输入顶点集");
	for(i=0;i<G->vexnum;i++){
		scanf("%d",&G->vertices[i].data);
		getchar();
	}
	for(i=0;i<G->vexnum;i++)
		G->vertices[i].fristarc=NULL;
	for(k=0;k<G->arcnum;k++){
		printf("请输入一条边的两个结点:");
		scanf("%d%d",&i,&j);
		m=LocateVex(G,i);// 不能用输入的结点信息,这里要使用 结点信息数组中的 索引值,不然会出错 
		n=LocateVex(G,j);
		s=(ArcNode*)malloc(sizeof(ArcNode));// 头插法 建立链表 
		s->adjvex=j;
		s->nextarc=G->vertices[m].fristarc;
		G->vertices[m].fristarc=s;
		//生成对称结点   无向图  
		s=(ArcNode*)malloc(sizeof(ArcNode));
		s->adjvex=i;
		s->nextarc=G->vertices[n].fristarc;
		G->vertices[n].fristarc=s;
	}
}
void readGraph(ALGraph G){ //深度递归 
	int i,j;
	ArcNode *p;
	for(i=0;i<G.vexnum;i++){
		printf("%d : ",G.vertices[i].data);// 结点信息保存在 data 域中    
		for(p=G.vertices[i].fristarc;p;p=p->nextarc)
			printf(" %d",p->adjvex);
		printf("\n");
	}
}
// 求连通个数   深度优先算法 
void DFS(int x,ArcNode *p,ALGraph *G){
	vis[x]=1;  // 将 x 标记已访问   
	for(p = G->vertices[x].fristarc;p;p=p->nextarc){ //找到 链表  依次访问    和 readGraph 的for循环一样  深度递归算法 
		if(!vis[LocateVex(G,p->adjvex)]){ // p->adjvex 当前结点未访问  
			int i=LocateVex(G,p->adjvex); 
			DFS(i,p,G); 
		}
	}
}
int main(){
	ALGraph G;
	creatGraph(&G);
	readGraph(G);
	int count=0;
	for(int i=0;i<G.vexnum;i++)
		vis[i]=0;
	ArcNode *p;
	for(int i=0;i<G.vexnum;i++){
		p = G.vertices[i].fristarc; 
			if(!vis[i]){
				DFS(i,p,&G);
				count++;  // 每当深度调用完毕,意味着:走到头了。是一个连通分量,再判断 有没有未被访问的结点,如果有继续,没有循环结束。count即为连通分量个数 
			}
	}
	printf("连通分量个数为:%d",count);
}

运行结果实例:
请输入图的顶点数和边数:6 3
请依次输入顶点集
1 2 3 4 5 6
请输入一条边的两个结点:1 3
请输入一条边的两个结点:2 4
请输入一条边的两个结点:4 6
1 :  3
2 :  4
3 :  1
4 :  6 2
5 :
6 :  4
连通分量个数为:4
--------------------------------
Process exited after 11.75 seconds with return value 0
请按任意键继续. . .

你可能感兴趣的:(数据结构实验,数据结构,算法,图论)