1. 程式人生 > >資料結構——圖的儲存與遍歷(鄰接矩陣)

資料結構——圖的儲存與遍歷(鄰接矩陣)

圖的儲存與遍歷(鄰接矩陣)

#include<stdio.h>
#include<stdlib.h>

#define MAXVEX      20             /*最大頂點個數*/ 
#define INFINITY    32767          /*表示無窮,可自定義*/

#define Elem        int
#define FALSE       0
#define OK          1
#define TRUE        1

typedef char VertexType;

typedef struct{
	int arcs[MAXVEX][MAXVEX];            //鄰接矩陣,邊的資訊
	VertexType vexs[MAXVEX];        //頂點資訊 
	int vexnum;      //頂點數目 
	int arcnum;      //邊(弧)數目 
	
}AdjMatrix; 

//根據名稱得到指定頂點在頂點集合中的下標
int getIndexOfVexs(char vex,AdjMatrix *MG)
{
	for(int i=1;i<=MG->vexnum;i++)
	{
		if(MG->vexs[i]==vex) return i;
	}
	return 0;
}

//用鄰接矩陣建立圖 
void Create(AdjMatrix *MG){
	int v1,v2;
	char c1,c2;

	printf("請輸入頂點數目: ");         //輸入頂點數 
	scanf("%d",&MG->vexnum);
	printf("請輸入邊的數目: ");         //輸入邊數 
	scanf("%d",&MG->arcnum);
	getchar();
	
    //輸入各頂點資訊 
	for(int i=1;i<=MG->vexnum;i++)
	{
		printf("請輸入第%d個頂點(char): ",i);    //請輸入各頂點資訊   
		scanf("%c",&MG->vexs[i]);
		getchar();
	}
	
	//初始化鄰接矩陣
	for(int i=1;i<=MG->vexnum;i++)
		for (int j=1;j<=MG->vexnum;j++)
			MG->arcs[i][j]=0;               /*如果是網則賦值INFINITY */ 
			
	//輸入邊的資訊,建立鄰接矩陣
	for(int k=1;k<=MG->arcnum;k++)
	{
		printf("請輸入第%d個邊連線的兩個頂點v1(char) v2(char): ",k);  //請輸入有關係的兩個頂點 
		scanf("%c %c",&c1,&c2);
		v1=getIndexOfVexs(c1,MG);
		v2=getIndexOfVexs(c2,MG);
		MG->arcs[v1][v2]=1; 
		MG->arcs[v2][v1]=1;   //無向圖為對稱矩陣
		getchar();
	}
}

//列印圖的資訊 
void Printf(AdjMatrix MG)
{
	printf("頂點數目為: %d\n",MG.vexnum);
	printf("邊的數目為: %d\n",MG.arcnum);
	printf("頂點: ");
	for(int i=1;i<=MG.vexnum;i++)
		printf("%c",MG.vexs[i]);
		
	printf("\n鄰接矩陣為: \n");
	for(int i=1;i<=MG.vexnum;i++)
	{
		for(int j=1;j<=MG.vexnum;j++)
			printf("%d",MG.arcs[i][j]);
			
		printf("\n");
	}
}

/******************遞迴深度優先遍歷函式***********************/
void visit(AdjMatrix G,int v){
		printf("%c",G.vexs[v]);
}

int FirstAdjVex(AdjMatrix G,int v){    //尋找圖G中v的第一個鄰接點
	 for(int i=1;i<G.vexnum;i++){
	 	if(G.arcs[v][i]!=0) return i;
	 }
	 return -1;
}
 
int NextAdjVex(AdjMatrix G,int v,int w){   //尋找圖G中v頂點在w之後的下一個鄰接點
	 for(int i=w+1;i<G.vexnum;i++){
	 	if(G.arcs[v][i]!=0) return i;
	 }
	 return -1;
} 

int visited[MAXVEX]={0};  //訪問標誌陣列
void DFS(AdjMatrix G,int v){   //遞迴深度優先遍歷連通子圖 
	visit(G,v);    //檢視v; 
	visited[v]=1;
	int w=FirstAdjVex(G,v);  //圖G中v的第一個鄰接點 
	while(w!=-1){  //如果沒有鄰接點則返回-1
		if(!visited[w]) DFS(G,w); //如果w沒有被訪問過,則對w進行深度優先遍歷 
		w=NextAdjVex(G,v,w);    //尋找圖G中v的下一個鄰接點 
	} 
} 

void TraverseG(AdjMatrix G){    //深度優先遍歷圖 
	for(int v=1;v<=G.vexnum;v++)  //標誌陣列初始化 
		visited[v]=0;
	printf("\n深度優先遍歷:");	
	for(int v=1;v<=G.vexnum;v++){
		if(!visited[v]) DFS(G,v);
	}	
}


/*******************廣度優先遍歷函式(相似與二叉樹的層次遍歷)***********************/
              /********佇列函式*******/
 typedef struct array{      //定義佇列結構 
 	Elem elem;
 	struct array *next;
 }*PLArray; 
 
 typedef struct Node_D{
 	PLArray  front;   //指向隊頭 
 	PLArray  rear;    //指向隊尾 
 	int len;          //佇列實際長度 
 }*pNode;
 
void InitArray(pNode &S){    //構造空佇列 
	PLArray q=(PLArray)malloc(sizeof(PLArray)); //申請新結點
	S=(pNode)malloc(sizeof(pNode)); 
	S->front=q;
	S->rear=q;
	S->front->next=NULL;
	S->len=0; 
	
}

int Push(pNode &S,Elem e){    //插入資料e為佇列的隊尾 
	PLArray p=(PLArray)malloc(sizeof(PLArray));  //申請新結點 
	p->elem=e;
	
	p->next=NULL;
	S->rear->next=p;   //將結點插入到隊尾 
	S->rear=p;         //修改隊尾指標 
	S->len++; 
}

int Pop(pNode &S,Elem &e){    //刪除隊頭元素,,用e返回其刪除資料 
	if(S->front==S->rear)  return FALSE;
	PLArray p=S->front->next;   //p指向隊頭
	e=p->elem;
	S->front->next=p->next;   //修改頭結點的指標域
	if(S->rear==p) S->rear=S->front;   //最後元素被刪除
	S->len--;
	return OK ;
}

int ArrayEmpty(pNode &S){    //判斷佇列是否為空 
	if(S->len==0)  return TRUE;
	else           return FALSE;
} 

int Refer(pNode &S,Elem &e) {  //查詢隊頭元素 
	e=S->front->next->elem;
}

/*廣度優先遍歷的 visit函式,FirstAdjVex函式,NextAdjVex函式  功能相同不重複定義 */
int visited2[MAXVEX]={0};  //訪問標誌陣列
void BFS(AdjMatrix G,int v){  //廣度優先遍歷連通子圖
	visit(G,v);
	visited2[v]=1;
	pNode Q;
	InitArray(Q);  //建立空佇列
	Push(Q,v);     //入隊
	while(!ArrayEmpty(Q)){    //當佇列非空時
		Pop(Q,v);     //出隊
		int w=FirstAdjVex(G,v);  //圖G中v的第一個鄰接點
		while(w!=-1){            //遍歷v的所有鄰接點 
			if(!visited2[w]){
				visit(G,w);
				visited[w]=1;
				Push(Q,w);
			}
			w=NextAdjVex(G,v,w);    //尋找圖G中v的下一個鄰接點
		} 
		 
	}	 
} 

void TraverseG_2(AdjMatrix G){    //廣度優先遍歷圖 
	for(int v=1;v<=G.vexnum;v++)  //標誌陣列初始化 
		visited2[v]=0;
	printf("\n廣度優先遍歷:");	
	for(int v=1;v<=G.vexnum;v++){
		if(!visited2[v]) DFS(G,v);
	}	
}

int main(){
	AdjMatrix MG;
	Create(&MG); 
	Printf(MG);
	TraverseG(MG);
	TraverseG_2(MG);
	return 0;
}