1. 程式人生 > >圖的廣度優先遍歷BFS(鄰接矩陣實現)c語言

圖的廣度優先遍歷BFS(鄰接矩陣實現)c語言

廣度優先遍歷也叫廣度優先搜尋(Breadth First Search)。它的遍歷規則:
  1. 先訪問完當前頂點的所有鄰接點。
  2. 先訪問的頂點的鄰接點先於後訪問頂點的鄰接點被訪問。

演算法思想

使用佇列的資料結構(FIFO (First In First Out)),將一個頂點加入佇列,然後在佇列中刪除頂點,並且將該頂點相連的所有頂點依次加入佇列中,再迴圈處理這些頂點,直至所有頂點均被訪問。(類似樹的層序遍歷)

演算法所需:

對佇列的基本操作熟悉

程式碼實現如下:

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

#define MAX 10
#define INFINITY 65535
#define TRUE 1
#define FALSE 0

typedef char VertexType;
typedef int EdgeType;

typedef int Boole;  //布林型別 儲存TRUE FALSE
Boole visited[MAX];    //訪問標誌陣列 

typedef int QElemType;    //鏈佇列的資料型別 
typedef int Status; 


/*鄰接矩陣結構*/ 
typedef struct
{
	VertexType vexs[MAX];   //頂點表 
	EdgeType arc[MAX][MAX];   //鄰接矩陣 可看作邊表   
	int numVertexes,numEdges;   //頂點數和邊數 
}MGraph;

/*佇列結構*/
typedef struct QNode
{
	QElemType data;
	struct QNode *next;
}QNode,*QueuePtr;

typedef struct
{
	QueuePtr front,rear;  //隊頭隊尾指標 
}LinkQueue;
 

//構造鄰接矩陣
void create(MGraph *G)
{
	int i,j,k,w;
	printf("請輸入頂點數和邊數:\n");
	scanf("%d%d",&G->numVertexes,&G->numEdges);
	fflush(stdin);
	for(i=0;i<G->numVertexes;i++)     //建立頂點表
	{ 
		printf("\n第%d個頂點",i+1);
		scanf("%c",&G->vexs[i]);
		getchar();
	}
	
	for(i=0;i<G->numVertexes;i++)   //矩陣初始化 
		for(j=0;j<G->numVertexes;j++)
			G->arc[i][j]=INFINITY;
			
	for(k=0;k<G->numEdges;k++)
	{
		printf("輸入邊(Vi,Vj)的上下標i,j和權w(空格隔開):");
		scanf("%d%d%d",&i,&j,&w);
		G->arc[i][j]=w;
		G->arc[j][i]=G->arc[i][j];
	}			 
} 

  //輸出鄰接矩陣 
void Output(MGraph *G)   
{
	int i,j,count=0;
	for(i=0;i<G->numVertexes;i++)
		printf("\t%c",G->vexs[i]);
	printf("\n");
	for(i=0;i<G->numVertexes;i++)
	{
		printf("%4c",G->vexs[i]);
		for(j=0;j<G->numVertexes;j++)
		{	
			
				printf("\t%d",G->arc[i][j]);
				count++;
				if(count%G->numVertexes==0)
				printf("\n");	
		} 
    }	 
 } 
 

//建立空佇列
Status InitQueue(LinkQueue &Q)
{
	Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
	if(!Q.front)
		exit(0);
	Q.front->next=NULL;
	return 1;	
} 

//入佇列
//將s作為新元素加入隊尾 
Status EnQueue(LinkQueue &Q,int i)
{
	QueuePtr s;
	s=(QueuePtr)malloc(sizeof(QNode));
	if(!s)
		exit(0);
	s->data=i;
	s->next=NULL;
	Q.rear->next=s;
	Q.rear=s;
	return 1;	
}

//檢驗是否為空
Status QueueEmpty(LinkQueue Q)
{
	if(Q.front->next==NULL)
		return 0;
	else
		return 1;	
 } 

//出佇列
Status DeQueue(LinkQueue *Q,int *i)
{
	QueuePtr p;
	if(Q->front==Q->rear)
		return 0;
	p=Q->front->next;     //該寫法值得商榷
						//相當於p儲存第一個結點
	*i=p->data;
	Q->front->next=p->next;
	
	if(p==Q->rear)   //若隊頭是隊尾	,刪除後將rear指向頭結點		
		Q->rear==Q->front;
	free(p);
	return 1;			
 } 



/*廣度遍歷*/ 
void BFSTraverse(MGraph G)
{

	int i,j;
	LinkQueue Q;
	for(i=0;i<G.numVertexes;i++)
		visited[i]=FALSE;
	InitQueue(Q);          //&的用法??     初始化佇列    
	for(i=0;i<G.numVertexes;i++)
	{
		if(!visited[i])    //未訪問過 該頂點 
		{
			visited[i]=TRUE;
			printf("%c->",G.vexs[i]);
			EnQueue(Q,i);      //將其入佇列 
			while(!QueueEmpty(Q))
			{
				DeQueue(&Q,&i);    //將隊中元素出佇列,賦值給i 
				for(j=0;j<G.numVertexes;j++)
				{
					if(G.arc[i][j]==1&&!visited[j])      //其他頂點與該頂點存在邊   且未訪問過 
					{
						visited[j]=TRUE;
						printf("%c",G.vexs[j]);
						EnQueue(Q,j);                 //入佇列 
					}
					
				} 
			} 
		}
	}
} 


int main()
{
	MGraph G;
	create(&G);
	printf("鄰接矩陣資料如下:\n");
	Output(&G);
	printf("\n");
	BFSTraverse(G); 
	printf("\n圖遍歷完畢");
	return 0;	 
	
}