基於鄰接矩陣和鄰接表的兩種方法實現無向圖的BFS和DFS
阿新 • • 發佈:2019-01-09
廣度優先搜尋(Breadth-First-Search)和深度優先搜尋(Deep-First-Search)是搜尋策略中最經常用到的兩種方法,特別常用於圖的搜尋.
BFS的思想:
從一個圖的某一個頂點V0出發,首先訪問和V0相鄰的且未被訪問過的頂點V1、V2、……Vn,然後依次訪問與V1、V2……Vn相鄰且未被訪問的頂點。如此繼續,找到所要找的頂點或者遍歷完整個圖。我們採用佇列來儲存訪問過的節點。
DFS的思想:
深度優先搜尋所遵循的策略就是儘可能“深”的在圖中進行搜尋,對於圖中某一個頂點V,如果它還有相鄰的頂點且未被訪問,則訪問此頂點。如果找不到,則返回到上一個頂點。這一過程一直進行直到所有的頂點都被訪問為止。 DFS可以搜尋出從某一個頂點到另外的一個頂點的所有路徑。 由於要進行返回的操作,我們採用的是遞迴的方法。
鄰接表:
鄰接表是圖的一種鏈式儲存結構。在鄰接表中,對圖中的每個頂點vi建立一個單鏈表,把魚vi相鄰的頂點放在這個連結串列中。
鄰接矩陣:
鄰接矩陣是表示頂點之間相鄰關係的矩陣。設G(V,E)是具有n個頂點的無向圖,則其對應了一個n階方陣。設這個方陣為A,則對於A[i][j]有兩種取值,當A[i][j]=1時,表示頂點i和頂點j是連通的;當A[i][j]=0時,表示頂點i和頂點j是不連通的。
基於鄰接矩陣的DFS:
<span style="font-size:14px;">//基於鄰接矩陣的DFS,時間複雜度為O(n^2) #include <stdio.h> #include <string.h> const int GNumber = 8;//儲存節點個數 int G[GNumber][GNumber];//儲存鄰接矩陣 int color[GNumber];//儲存節點狀態 void DFS_Visit(int G[][GNumber], int i, int n){ int j; color[i] = 1; for(j=0; j< n; j++){ if(G[i][j] && !color[j]){ printf(" V%d ", j+1); color[j] = 1; DFS_Visit(G, j, n); } } } void DFS(int G[][GNumber], int n){ int i; memset(color, 0, sizeof(color)); for(i=0; i<n; i++){//遍歷每一個節點 if(!color[i]){//判斷是否訪問 printf(" V%d ", i+1); DFS_Visit(G,i,n); printf("\n"); } } } int main(){ FILE *fr; int i,j; fr = fopen("測試用例.txt","r"); if(!fr){ printf("fopen failed\n"); return -1; } while(fscanf(fr,"%d%d", &i, &j) != EOF){ G[i-1][j-1] = 1; G[j-1][i-1] = 1; } DFS(G,GNumber); getchar(); return 0; }</span>
基於鄰接矩陣的BFS:
<span style="font-size:14px;">//基於鄰接矩陣的BFS,時間複雜度為O(n^2) #include <stdio.h> #include <string.h> const int GNumber = 8;//儲存節點個數 int G[GNumber][GNumber];//儲存鄰接矩陣 int color[GNumber];// 防止迴環,記錄節點狀態 struct Queue{//用陣列模擬佇列 int queue[GNumber]; int start; int end; }MyQueue; void BFS(int G[][GNumber], int n){ int j; MyQueue.queue[MyQueue.end++] = 0; color[0] = 1; while(MyQueue.end != MyQueue.start){ for(j=0; j<n; j++){ if(G[MyQueue.start][j] && !color[j]){ color[j] = 1; MyQueue.queue[MyQueue.end++] = j; } } printf(" V%d ", MyQueue.queue[MyQueue.start++]+1); } } int main(int argc, char **argv){ FILE *fr; int i,j; fr = fopen("測試用例.txt","r"); if(!fr){ printf("fopen failed\n"); return -1; } //printf("%d %d\n",MyQueue.start,MyQueue.end); while(fscanf(fr,"%d%d", &i, &j) != EOF){ G[i-1][j-1] = 1; G[j-1][i-1] = 1; } memset(&MyQueue, 0, sizeof(MyQueue)); memset(color, 0, sizeof(color)); BFS(G,GNumber); getchar(); return 0; }</span>
基於鄰接表的BFS和DFS:
<span style="font-size:14px;">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 8 //最大頂點數
typedef struct node{ //邊節點
int adjvex; //該邊指向的頂點位置
//int weight
struct node* next; //指向下一條邊的指標
}ArcNode;//邊表結點
typedef struct VNode{
int vertex;
ArcNode* firstarc; //指向第一條依附該頂點的指標
}VNode;//頂點表結點
typedef VNode Adjlist[MAX+1];//adj_list是鄰接表型別
typedef struct {
int n, m;//圖中頂點數和邊數
Adjlist adjlist;//鄰接表
}ALGraph;
void create_algraph(ALGraph* g)//建立無向圖的鄰接表
{
ArcNode* newnode;
int i, j, k;
printf("please input node number and edge number: ");
scanf("%d%d", &g->n, &g->m);
printf("node number = %d, edges = %d\n", g->n, g->m);
for(i = 1; i <= g->n; i++){
g->adjlist[i].vertex = i;
g->adjlist[i].firstarc = NULL;
}
printf("please input new edge: \n");//用相鄰的兩個頂點來表示邊
for(k = 1; k <= g->m; k++){
scanf("%d%d", &i, &j);
//printf("\n");
newnode = (ArcNode* )malloc(sizeof(ArcNode));
newnode->adjvex = j;
//newnode->weight = 0;
newnode->next = g->adjlist[i].firstarc;
g->adjlist[i].firstarc = newnode;
newnode = (ArcNode* )malloc(sizeof(ArcNode));
newnode->adjvex = i;
//newnode->weight = 0;
newnode->next = g->adjlist[j].firstarc;
g->adjlist[j].firstarc = newnode;
}
}
void pr_algraph(ALGraph* g)//輸出鄰接表
{
ArcNode* node;
int i;
for(i = 1; i<= g->n; i++){
node = g->adjlist[i].firstarc;
printf("g->adjlist[%d] = %d: ", i, g->adjlist[i].vertex);
while(node != NULL){
printf("%d \t", node->adjvex);
node = node->next;
}
printf("\n");
}
}
int visted[MAX+1];//記錄節點狀態
void DFS(ALGraph *g,int v)
{
visted[v] = 1; //訪問初始點
ArcNode *p = g->adjlist[v].firstarc;
while(p!=NULL)
{
if (visted[p->adjvex]==0){ //如果沒有被訪問過,則遞迴呼叫DFS訪問
printf("%d ",p->adjvex);
DFS(g,p->adjvex);
}
p = p->next;//繼續下一條邊
}
//printf("\n");
}
void BFS(ALGraph *g,int v)
{
//for (int i=0;i<g->n;i++) visted[i] = 0;
int queue[MAX],front,rear;
front = rear = 0;
rear = (rear+1)%MAX;
queue[rear] = v; //v頂點入隊
int u;
ArcNode *p;
while(/*rear!=0*/front!=rear)//當佇列滿時
{
front = (front+1)%MAX;
u = queue[front];
p = g->adjlist[u].firstarc;
while(p!=NULL) //首先訪問u的所有節點
{
if (visted[p->adjvex]==0)
{
visted[p->adjvex] = 1; //訪問p->adjvex節點,標記為訪問
rear = (rear+1)%MAX;
printf("%d ",p->adjvex);
queue[rear] = p->adjvex; //p->adjvex節點入隊
}
p = p->next;
}
}
printf("\n");
}
int main(int argc, char** argv)
{
ALGraph* g;//定義一個無向圖
g = (ALGraph* )malloc(sizeof(ALGraph));
printf("begin create algraph\n");
create_algraph(g);
printf("finish create algraph\n");
printf("the algraph is:\n");
pr_algraph(g);
memset(visted,0,sizeof(visted));
visted[1]=1;
printf("BFS is:\n");
printf("1 ");
BFS(g,1);
memset(visted,0,sizeof(visted));
printf("DFS is:\n");
printf("1 ");
DFS(g,1);
printf("\n");
return 0;
}
</span>
鄰接矩陣和鄰接表都是實現BFS和DFS的方法,鄰接矩陣時間複雜度為O(n^2),鄰接表的時間複雜度為O(n+e);因此鄰接矩陣適用於稠密圖,鄰接表適用於稀疏圖。