【数据结构随笔】图的深度优先搜索(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;

posted @ 2021-11-07 22:06  天涯海角寻天涯  阅读(1112)  评论(0编辑  收藏  举报