【數據結構隨筆】圖的深度優先搜索(DFS)與廣度優先搜索(BFS)


本文介紹圖的兩種重要遍歷算法:深度優先搜索與廣度優先搜索

一.深度優先搜索(DFS)

深度優先搜索是一個不斷探查與回溯的過程,其思想是遞歸。樹的先序遍歷可以看成是深度優先搜索的一種情況。在探查的每一步中,算法都記錄有一個當前頂點。最初的當前頂點,也即函數指定的開始頂點。在每一步的探查過程中,首先訪問當前頂點v,並立刻將其訪問標志visited[v]設為true。然后將與其鄰接的任一還未訪問過的頂點作為當前頂點,重復上述步驟。當當前頂點的的所有鄰接頂點均已訪問過后,退回到上一步時訪問的頂點,並將其設為當前頂點,繼續探查其是否還有未訪問過的頂點。當所有頂點的visited均已設為true時,證明該連通圖的所有頂點均已至少訪問一遍,此時遞歸工作棧逐步退棧,程序結束。

給出一個用DFS遍歷的示例:

給出圖(a)的以0為最初頂點的DFS的工作過程:

從頂點0開始進行的深度優先遍歷過程:0,1,(0),3,(1),7,(3),4,(1),(7),(back to 7),5,2,(0),6,(2),(7),(back to 2),(5),(back to 5),(7),(back to 4),(back to 7),(5),(6),(back to 3),(back to 1),(4),(back to 0),(2)end;

DFS的偽代碼描述:

virtual void Graph::DFS(){
  bool* visited=new bool[n]; 
  for(int i=0;i<n;i++)
    visited=false;    
  DFS(0);
  delete []visited;
}

virtual void Graph::DFS(const int v){ //訪問當前頂點v的所有未訪問過的結點
  visited[v]=true;
  for(each vertex w adjacent to v)
    DFS(w);
}

代碼實現:

void DFS(Graphlnk& G, const int v) {
	int loc;
	int n = G.NumberOfVertex();   //圖中頂點個數
	bool* visited = new bool[n];
	for (int i = 0; i < n; i++)
		visited[i] = false;
	loc = G.GetVertexPos(v);  //獲取v對應的結點在圖中的位置
	DFS(G, loc, visited);  //遞歸子程序
	delete[]visited;
}

void DFS(Graphlnk& G, const int v, bool* visited) {
	std::cout << G.getValue(v) << " ";
	visited[v] = true;
	int w = G.getFirstNeighbor(v);  //獲取v的第一個鄰接結點
	while (w != -1) {
		if (visited[w]==false)
			DFS(G, w, visited);
		w = G.getNextNeighbor(v, w); //獲取v的鄰接結點的下一個鄰接結點
	}
}

其中的圖由鄰接表實現;

DFS時間復雜度的分析:初始化標志數組visited[]的時間復雜度為O(n);

如果圖以鄰接矩陣的形式表示,那么探查當前頂點v的所有鄰接結點的時間復雜度為O(n),因為需要遍歷矩陣第v行的n個結點;由於有n個頂點,故總體時間復雜度為O(n²)

如果圖以鄰接鏈表的形式表示,則只要遍歷當前頂點的鏈表即可,DFS訪問每一個頂點最多一次,若圖一共有e條邊,時間復雜度為O(e+n).

二.廣度優先搜索

與DFS不同,廣度優先搜索(BFS)不是一個探查與回溯的過程,而是一個層次遍歷的過程。在這個過程中,圖有多少頂點就要重復多少步,每一步都有一個當前頂點。最初的當前頂點是由主過程指定的當前頂點。在每一步中,首先訪問當前頂點v,並設置該頂點的訪問標志visited為true,然后依次訪問當前頂點的所有鄰接頂點w1,w2,......wn,然后再按順序依次訪問w1,w2,......wn所有未訪問的鄰接頂點,依次類推直到圖中的所有結點都被訪問。

由於BFS不是一個遞歸的過程,故需要一個隊列來記錄正在訪問的這一層以及上一層頂點,以便於繼續向下訪問。

依舊以上圖(a)為例,我們給出其廣度優先遍歷的序列:

0,1,23,4,5,6,7

BFS的偽代碼描述:

virtual void Graph::BFS(int v){
  bool* visited=new bool[n];
  fill(visited,visited+n,false);
  queue<int>Q;
  Q.push(v);
  visited[v]=true;
  while(!Q.empty()){
    v=Q.front();
    Q.pop();
    for (all vertices w adjacent to v)
      if(!visited[w]){
        Q.push(w);
        visited[w]=true;
      }
  }
    delete []visited;
}

代碼實現:

void BFS(Graphlnk& G, const int v) {
	int w;
	int n = G.NumberOfVertex();
	bool* visited = new bool[n];
	for (int i = 0; i < n; i++)
		visited[i] = false;
	int loc = G.GetVertexPos(v);
	std::cout << G.getValue(loc) << " ";
	visited[loc] = true;
	std::queue<int>Q;
	Q.push(loc);
	while (!Q.empty()) {
		loc = Q.front();
		Q.pop();
		w = G.getFirstNeighbor(loc);
		while (w != -1) {
			if (visited[w]==false) {
				std::cout << G.getValue(w) << " ";
				visited[w] = true;
				Q.push(w);
			}
			w = G.getNextNeighbor(loc, w);
		}
	}
	delete[]visited;
}

時間復雜度:同DFS;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM