1. 程式人生 > >無向圖的連通分量和生成樹

無向圖的連通分量和生成樹

//名詞解釋:
//一個連通圖(對於無向圖)的生成樹是一個極小的連通子圖,它含有途中所有的頂點,但只有足以構成一個樹的n-1條邊。
//下面的程式為通過DFS深度優先遍歷一個非連通圖(會生成>1的生成樹,用孩子兄弟鏈作為生成森林的儲存結構)。

#include "stdio.h"
#include "string.h"
#include "stdlib.h"



#define MAX_VERTEX_NUM 20//最大的頂點數

		

//邊結點
typedef struct Edge {
	struct Edge *next;//指向下一個邊的指標
	int index;//該邊所依賴的頂點的位置
}Edge;

//頂點
typedef struct  {
	char name[10];//頂點的名字
	Edge * first;//指向依賴該頂點的第一條邊	
}Vertex;


typedef struct  {
	int ver_num;//頂點的數
	int edge_num;//邊數
	Vertex vertexs[MAX_VERTEX_NUM];
}Undigraph;


//根據名字找到頂點的位置
int get_location (Undigraph *ud,char * name) {
	int i;
	for (i = 0;i < ud->ver_num;i++) {
		if (0 == strcmp(name,ud->vertexs[i].name)) {
			return i;
		}
	}
	return -1;
}

//建立一個邊
Edge* new_edge () {
	Edge *edge = (Edge*)malloc(sizeof(Edge));
	if (NULL == edge) {
		exit(-1);
	}
	edge->next = NULL;
	return edge;
}
//建立無向圖
void create_undigraph (Undigraph * ud) {
	int k,i,j;
	char v1[10],v2[10];
	Edge *edge = NULL;
	scanf ("%d%d",&(ud->ver_num),&(ud->edge_num));//輸入頂點數和邊的數量
	//初始化頂點
	for (k = 0;k < ud->ver_num;k++) {
		scanf("%s",ud->vertexs[k].name);
		ud->vertexs[k].first = NULL;
	}
	//初始化邊
	for (k = 0; k < ud->edge_num;k++) {
		scanf ("%s %s",v1,v2);
		i = get_location (ud,v1);
		j = get_location (ud,v2);

		edge = new_edge ();
		edge->index = j;
		edge->next = ud->vertexs[i].first;
		ud->vertexs[i].first = edge;

		edge = new_edge ();
		edge->index = i;
		edge->next = ud->vertexs[j].first;
		ud->vertexs[j].first = edge;
	}
}

//返回下標為v的頂點的第一個鄰接點,有返回,沒有返回NULL
Edge* first_adjacent_vertex (Undigraph *ud,int v) {
		if (v < 0 || v >= ud->ver_num) {
			return NULL;
		}
		return ud->vertexs[v].first;
}

//返回edge後的第一個鄰接點,有返回,沒有返回NULL
Edge* next_adjacent_vertex (Edge *edge ) {
		if (NULL == edge) {
			return NULL;
		}
		return edge->next;
}


//用於記錄頂點是否被訪問過的標誌陣列
int visited[MAX_VERTEX_NUM];


//------樹的二叉連結串列(孩子-兄弟)儲存表示---------
typedef struct CSNode {
	char name[10];//圖中頂點的名字
	struct CSNode *first_child,*next_sibling;
}CSNode,*Tree;



CSNode * create_CSNode (){
	CSNode * node = (CSNode*)malloc(sizeof(CSNode));
	if (NULL == node) {
		exit(-1);
	}
	node->first_child = NULL;
	node->next_sibling = NULL;
	return node;
}
//
void dfs_tree (Undigraph *ud,int v,Tree *t) {
		Edge *edge = NULL;
		CSNode *p = NULL;
		strcpy((*t)->name,ud->vertexs[v].name);
		visited[v] = 1;
		 edge = first_adjacent_vertex (ud,v);
		while (NULL != edge) {
			if (0 == visited[edge->index]) {
				CSNode *node = create_CSNode ();
				if (NULL == (*t)->first_child) {
					(*t)->first_child = node;
				}else {
					p->next_sibling = node;
				}
				p = node;
				dfs_tree (ud,edge->index,&p);
			}
			edge = edge->next;
		}
}


void dfs_forest (Undigraph *ud,Tree *t) {
	int i;
	CSNode *node = NULL;
	CSNode *p = NULL;
	memset (visited,0,sizeof(visited));
	for (i = 0;i < ud->ver_num;i++) {
		if (0 == visited[i]) {
			node = create_CSNode ();
			if (NULL == (*t)) {//根節點
				(*t) = node;
			}else {
				p->next_sibling = node;//其他生成樹的根
			}
			p = node;
			dfs_tree (ud,i,&p);
		}
	}
}

//遍歷二叉樹

void traverse (Tree  tree) {
	if (tree != NULL) {
		printf ("%s-",tree->name);
		traverse (tree->first_child);
		traverse (tree->next_sibling);
	}
}
int main () {
		Undigraph ud;
		Tree  tree = NULL;
		create_undigraph (&ud);
		dfs_forest (&ud,&tree);
		traverse (tree);
		return 0;
}