深度优先遍历(搜索)(DFS)

来源:互联网 发布:淘宝天猫 编辑:程序博客网 时间:2024/05/22 07:07

深度优先遍历(Depth_First_Search),也称为深度优先搜索,简称DFS。


无向图

无向图对应的邻接矩阵

深度优先遍历其实就是一个递归的过程,像一棵树的前序遍历。它从图中某个顶点v出发,访问此顶点,然后从v的未访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到。事实上,这里指的是连通图,对于非连通图,只需要对它的连通分量分别进行深度优先遍历,即在先前一个顶点进行一次深度优先遍历后,若图中尚有顶点未被访问则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直到图中所有顶点都被访问到为止。

对以邻接矩阵存储的图进行DFS。如下:

#include<iostream>using namespace std;/************************************************************************//* 以下是图的邻接矩阵存储                                               *//************************************************************************/typedef char VertexType;//顶点数据类型  typedef int EdgeType;//边上的权值数据类型   const int MAXVEX = 100;//最大顶点数   const int INFINITY = 65535;//代表无穷大   typedef struct  {  VertexType vexs[MAXVEX];//顶点表   EdgeType arc[MAXVEX][MAXVEX];//邻接矩阵,可看作边表   int numVertexes, numEdges;//图中当前的顶点数和边数   }MGraph;   void CreateMGraph(MGraph *G)  {  int i,j,k,w;  printf("请输入顶点数和边数:\n");  scanf("%d,%d",&G->numVertexes,&G->numEdges);  for(i=0; i<G->numVertexes; i++)  {  fflush(stdin);  printf("请输入顶点%d的值:\n",i);  scanf("%c",&G->vexs[i]);   }  for(i=0; i<G->numVertexes; i++)//初始化邻接表   {          for(j=0; j<G->numVertexes; j++)          {  if(i == j)  G->arc[i][j] = 0;  else  G->arc[i][j] = INFINITY;          }  }  for(k=0; k<G->numEdges; k++)//在邻接表中写入具体数据   {  printf("请输入边(vi,vj)上的下标i,j和权w:\n");  scanf("%d,%d,%d",&i,&j,&w);  G->arc[i][j] = w;  G->arc[j][i] = G->arc[i][j];//因为是无向图,矩阵对称   }  }  /************************************************************************//* 以下是DFS                                                            *//************************************************************************///const int MAX = 100;bool visited[MAXVEX];void DFS(MGraph G,int i){int j;visited[i] = true;printf("%c ",G.vexs[i]);for(j=0; j<G.numVertexes; j++)if(1==G.arc[i][j] && !visited[j])//这里为简洁,构造图的时候权值都设为了1DFS(G,j);}void DFSTraverse(MGraph G){   int i;   for (i=0; i<G.numVertexes; i++)   {   visited[i] = false;   }   for (i=0; i<G.numVertexes; i++)   {   if (!visited[i])   {DFS(G,i);   }   }}int main(){    MGraph G;      CreateMGraph(&G);      for(int i=0; i<G.numVertexes; i++)      {  for(int j=0; j<G.numVertexes; j++)  {  printf("%d ",G.arc[i][j]);  }  printf("\n");      }   DFSTraverse(G);   printf("\n");   getchar();   return 0;}
结果

对于图的邻接表结构,只是将数据换成了链表。如下:

#include<iostream>  using namespace std;  typedef char VertexType;//顶点数据类型  typedef int EdgeType;//边上的权值数据类型   const int MAXVEX = 100;//最大顶点数   const int INFINITY = 65535;//代表无穷大   typedef struct EdgeNode//边表结点  {  int adjvex;//邻接点域,存储该点对应的下标  EdgeType weight;//存储权值,对于非网图可以不需要  struct EdgeNode *next; //链域,指向下一个邻接点  }EdgeNode;  typedef struct VertexNode//顶点表结点  {  VertexType data;  EdgeNode *firstedge;  }VertexNode,AdjList[MAXVEX];  typedef struct//图结构  {  AdjList adjList;  int numVertexes,numEdges;  }GraphAdjList;  void CreateALGraph(GraphAdjList *G)  {  int i,j,k,w;  EdgeNode *e;  printf("输入顶点数和边数:\n");  scanf("%d,%d",&G->numVertexes,&G->numEdges);  for(i=0; i<G->numVertexes; i++)  {  fflush(stdin);  printf("请输入顶点%d的值\n",i);  scanf("%c",&G->adjList[i].data);  G->adjList[i].firstedge = NULL;  }for (k=0; k<G->numEdges; k++)  {  fflush(stdin);  printf("请输入边(vi,vj)上的下标i,j和权w:\n");  scanf("%d,%d,%d",&i,&j,&w);  e = (EdgeNode *)malloc(sizeof(EdgeNode));  e->adjvex = j;  e->weight = w;  e->next = G->adjList[i].firstedge;  G->adjList[i].firstedge = e;  e = (EdgeNode *)malloc(sizeof(EdgeNode));//无向图[i][j]与[j][i]权值相同,可以一次将i->j与j->i都进行赋值,如果是有向图则只需要一次赋值  e->adjvex = i;  e->weight = w;  e->next = G->adjList[j].firstedge;  G->adjList[j].firstedge = e;  }  }  /************************************************************************//* 以下为DFS                                                            *//************************************************************************/bool visited[MAXVEX];void DFS(GraphAdjList GL,int i){  EdgeNode *p;  visited[i] = true;  printf("%c ",GL.adjList[i].data);  p = GL.adjList[i].firstedge;  while(p)  {  if(!visited[p->adjvex])  DFS(GL,p->adjvex);  p = p->next;  }}void DFSTraverse(GraphAdjList GL){   int i;   for(i=0; i<GL.numVertexes; i++)   {   visited[i] = false;   }   for (i=0; i<GL.numVertexes; i++)   {   if(!visited[i])   DFS(GL,i);   }}int main()  {  GraphAdjList graphA;  CreateALGraph(&graphA);  for (int i=0; i<graphA.numVertexes; i++)  {  cout<<graphA.adjList[i].data<<"-> ";  EdgeNode *tempNode = graphA.adjList[i].firstedge;  while (NULL != tempNode)  {  cout<<"["<< tempNode->adjvex<<"]["<<tempNode->weight<<"]->";  tempNode = tempNode->next;  }  tempNode = NULL;  cout<<endl;  }DFSTraverse(graphA);cout<<endl;return 0;  }  
结果:


以上由于链表使用了头插法,所以结果与邻接表的不一样,如果采用尾插法,就一样了。

邻接矩阵是2维数据,查找每个顶点需要访问矩阵中的所有元素,因此都需要O(n^2)的时间。

邻接表打邻接点所需要的时间取决于顶点和边的数量,所以是O(n+e)。

显然对于点多边少的稀疏图来说,邻接表结构使得算法在时间效率上大大提高。

相关

线性表的链式存储(链表)

图的邻接表存储结构

图的邻接矩阵存储结构


原创粉丝点击