圖的深度遍歷(DFS)和廣度遍歷(BFS)詳解

目錄

 

1 前奏(鄰接表)

2 深度遍歷

3 廣度遍歷


1 前奏(鄰接表)

圖作爲種比較繁瑣的數據結構,在進行圖的操作之前,首先應該用合適的數據類型來存儲圖的信息。

我們使用鄰接表來存儲,它是一種鏈式的存儲結構。所謂鄰接表就是對途中的每個頂點建立一個單鏈表。看一下下面的定義就明白了。

鄰接表的定義如下:

//邊
typedef struct ArcNode
{
	int adjvex;//該邊所指向的節點的位置
	struct ArcNode* nextarc;//指向下一條邊的指針
	int info;//存儲邊的相關信息,比如權重
}ArcNode;
//頂點
typedef struct VNode
{
	char data;//頂點信息
	ArcNode* firstarc;//指向第一條邊的指針
}VNode;
//鄰接表的定義
typedef struct AGraph
{
	VNode adjlist[MAXSIZE];//鄰接表,裏面存儲着圖種的所有頂點
	int n;//頂點的個數
	int e;//邊的個數
}AGraph;

2 深度遍歷

圖的深度優先搜索遍歷(DFS)類似於二叉樹的先序遍歷。它的基本思想是,從訪問節點v出發,並將其標爲已訪問過,然後選取與v鄰接的未被訪問過的任何一個頂點w,並訪問它,再選取與w鄰接的未被訪問的任一頂點並訪問,以重複進行。當一個頂點所有的鄰接頂點都被訪問過時,則依次退回到最近被訪問過的頂點,若該頂點還有其他鄰接頂點未被訪問,則從這些未被訪問的頂點中取一個頂點並重覆上述訪問過程,直至所有的頂點都被訪問過爲止。

 

我們假設從頂點A出發開始訪問,那麼可能的訪問序列有:

  • A,D,C,E,B
  • A,D,E,C,V
  • A,C,D,B,E

不限於以上三種,這與圖的鄰接表有關。

接下來是代碼的實現:

首先我們看一個連通圖的深度優先搜索遍歷:

int vist[MAXSIZE];//用於記錄訪問過的節點,0代表未訪問,1代表已訪問
//G爲鄰接表,v爲起始節點
void DFS(AGraph* G, int v)
{
	ArcNode* p;
	vist[v] = 1;
	cout << v << endl;
	p = G->adjlist[v].firstarc;//p指向v節點的第一條邊。
	while (p != NULL)
	{
		if (visit[p->adjvex] == 0)
			DFS(G, p->adjvex);//遞歸的進行訪問
		p = p->nextarc;//指向下一條邊
	}
}

上述的代碼只適合連通圖,如果一個圖中有孤立的節點,即當這個圖不是連通圖的時,就應該從所有的節點開始進行遍歷,如下:

void dfs(AGraph* g)
{
	for (int i = 0; i < g->n; ++i)
            if(visit[i]==0)
		DFS(g, i);
}

3 廣度遍歷

圖的廣度優先搜索遍歷類似於樹的層次遍歷。它的基本思想是:首先訪問起始頂點v,然後選取與v鄰接的全部頂點進行訪問,再依次訪問鄰接頂點的鄰接頂點,以此類推,直至所有的頂點都被訪問。

上述圖從A出發,我們假設D,C,B分別是A指向的第一個、第二個和第三個節點,那麼廣度遍歷的序列爲:

A,D,C,B,E

連通圖的廣度遍歷的代碼如下所示:

void BFS(AGraph* G, int v, int visti[MAXSIZE])
{
	ArcNode* p;
	queue<int> que;
	cout << v << endl;
	visit[v] = 1;
	que.push(v);
	while (!que.empty())
	{
		int j = que.top();//得到隊頭元素
		que.pop();//出隊
		p = G->adjlist[j].firstaec;
		while (p != NULL)
		{
			if (visit[] p->adjvex == 0)
			{
				cout << p->adjvex << endl;
				visit[p->adjvex] = 1;
				que.push(p->adjvex);
			}
			p = p->nextarc;//指向下一條邊
		}
		
	}
}

上述代碼是針對連通圖的,那麼對於非連通圖,需要從不同的節點開始進行訪問,充分考慮到孤立節點:

void bfs(AGraph* g)
{
	for (int i = 0; i < g->n; ++i)
            if(visit[i]==0)
		BFS(g, i);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章