1. 程式人生 > >算法系列—圖的深度優先搜尋(遞迴)/C++

算法系列—圖的深度優先搜尋(遞迴)/C++

圖的遍歷是指從圖的某一個頂點出發,按照某種方法沿著邊對圖中的頂點全部訪問一次。

ps:樹是一幅無環連通圖。互不相連的樹組成的集合 稱為森林。

連通圖的生成樹是它的一幅子圖,它含有圖中所有頂點且是一棵樹。

當且僅當一幅含有V個結點的圖G滿足下列五個條件之一時,他就是一棵樹:

1 G有V-1條邊且不含有環。

2 G有V-1條邊且是連通的。

3 G是連通的,且刪除任意一條邊都會使它不再連通。

4 G是無環圖,但新增任意一條邊都會產生一條環。

5 G中的任意一對頂點之間僅存在一條簡單路徑。

深度優先搜尋(DFS)的思想:

以圖的某個頂點V開始,訪問V的鄰接頂點w1,再訪問w1的鄰接頂點n1,直到當前所訪問的頂點的所有鄰接頂點都被訪問過了,然後回退到最近被訪問的頂點,如果該頂點還有未被訪問的點,則從改點繼續搜尋,否則繼續回退,直到回退到v。

深度優先搜尋中每條邊都會被訪問兩次,且第二次訪問時總會發現這個頂點已經被訪問過。

此處使用鄰接表表示圖,

C++程式碼實現如下:

//DFS.cpp
//有向圖
#include <iostream>
#include <list>
using namespace std;

class Graph
{
	int count = 0;//頂點數
	list<int> *adj;	//鄰接表
	void DFSUtil(int v, bool visited[]);
public:
	void addEdge(int v, int w);	//向圖中新增邊
	void DFS(int v);	//深度優先搜尋函式介面
	Graph(int count);
};

Graph::Graph(int count)
{
	this->count = count;
	adj = new list<int>[count];
}

void Graph::addEdge(int v, int w)
{
	adj[v].push_back(w);
}

void Graph::DFSUtil(int v, bool visited[])
{
	visited[v] = true;
	cout << v << " ";
	for(int w:adj[v])
	{
		if (!visited[w])
			DFSUtil(w, visited);
	}
}

void Graph::DFS(int v)
{
	bool *visited = new bool[count];
	for (int i = 0; i < count; ++i)
		visited[i] = false;
	DFSUtil(v, visited);
}

/* 測試 */
int main()
{
	Graph g(4);
	g.addEdge(0, 1);
	g.addEdge(0, 2);
	g.addEdge(1, 2);
	g.addEdge(2, 0);
	g.addEdge(2, 3);
	g.addEdge(3, 3);
	cout << "從2開始深度搜索" << endl;
	g.DFS(2);
	cout << endl;

	return 0;
}
上面的程式碼是假設從給定頂點可以訪問到圖的所有其他頂點。如果沒有這個假設,為了對圖作一個完整的深度優先遍歷,我們需要對每個頂點呼叫DFSUtil()。當然那之前需要先檢查頂點是否已經訪問過。

對於無向圖的深度優先搜尋,只是鄰接表不一樣,其他的都是一樣的。我們只需要修改addEdge(v, w)函式:

void Graph::addEdge(int v, int w)
{
  adj[v].push_back(w);         // 將w加到v的list
  adj[w].push_back(v);
}