邻接表的深度优先遍历

对《大话数据结构》P241——邻接表的深度优先遍历,进行了自己的理解并完善了代码。

邻接矩阵的深度优先遍历见http://www.cnblogs.com/hslzju/p/5399249.html

举个简单的无序图例子,为了节省时间传手稿。

首先用邻接表的存储结构创建该图,再进行深度优先遍历。

代码和解释如下(VS2012测试通过):

  1 #include <iostream>
  2 #include <stdlib.h>
  3 using namespace std;
  4 
  5 typedef struct EdgeNode//边表节点
  6 {
  7     int adjvex;//存储该顶点对应的下标
  8     struct EdgeNode *next;//指向该顶点的下一个邻接点
  9 }EdgeNode;
 10 
 11 typedef struct VertexNode//顶点表结点
 12 {
 13     char data;//顶点
 14     EdgeNode *firstedge;//边表头指针
 15 }VertexNode;
 16 
 17 typedef struct//图的邻接表存储结构
 18 {
 19     VertexNode adjList[4];//有4个VertexNode这种类型的顶点,定义一个数组adjList[4],每个元素是VertexNode类型
 20     int numVertexes,numEdges;//图中顶点数和边数,这里是4,5
 21 }GraphAdjList;
 22 
 23 GraphAdjList *CreateALGraph(GraphAdjList *Gp)//无向图的邻接表创建
 24 {
 25     Gp=(GraphAdjList *)malloc(sizeof(GraphAdjList));
 26     //申请一片GraphAdjList大小的类型很重要,否则Gp指向NULL(GL传的值是NULL),程序就运行崩溃了
 27     EdgeNode *pe;//定义边表指针类型pe
 28     cout << "input numNodes and numEdges:" << endl;
 29     cin >> Gp->numVertexes >> Gp->numEdges;//输入4 5
 30     for (int k = 0 ; k < Gp->numVertexes; k++)
 31     {
 32         cout << "input VertexType data:" << endl;
 33         cin >> Gp->adjList[k].data;//输入A B C D
 34         Gp->adjList[k].firstedge = NULL;//将边表头指针指向NULL,即置为0
 35     }
 36     for (int k = 0; k <  Gp->numEdges; k++)//建立边表
 37     {
 38         int i,j;
 39         cout << "input vi and vj:" << endl;
 40         cin >> i >> j;//每次循环依次输入0 1,0 2,0 3,1 2,2 3
 41 
 42         pe = (EdgeNode *)malloc(sizeof(EdgeNode));
 43         pe->adjvex = j;// 邻接序号为j
 44         pe->next = Gp->adjList[i].firstedge;//将pe的指针指向当前顶点指向的结点
 45         Gp->adjList[i].firstedge = pe;//将当前顶点的指针指向pe
 46 
 47         pe = (EdgeNode *)malloc(sizeof(EdgeNode));
 48         pe->adjvex = i;
 49         pe->next = Gp->adjList[j].firstedge;
 50         Gp->adjList[j].firstedge = pe;//无序图重复上面步骤
 51     }
 52     return Gp;
 53 }
 54 
 55 int visited[5]={0};//设置为全局变量,DFS和DFSTraverse函数都有用到
 56 //以下标为i的顶点adjList[i].data开始访问,进行一次深度优先递归,对连通图,可以访问到所有的顶点
 57 void DFS(GraphAdjList *G,int i)
 58 {
 59     EdgeNode *p;//定义指向边表的指针p
 60     visited[i]=1;//访问过的顶点标记为1
 61     cout<<G->adjList[i].data<<" ";//递归之前需要打印当前访问的顶点
 62 
 63     p=G->adjList[i].firstedge;//p指向该顶点的第一个边表
 64     while(p)//如果指向的边表不为空
 65     {
 66         if(!(visited[p->adjvex]))//如果p->adjvex为下标的顶点没有被访问过
 67             DFS(G,p->adjvex);//那就访问以p->adjvex为下标的顶点
 68         p=p->next;//回到调用处,把p移动到p->next,下面会用图说明调用顺序
 69     }
 70 }
 71 
 72 //邻接表的深度遍历
 73 void DFSTraverse(GraphAdjList *G)
 74 {
 75     for(int i=0;i<G->numVertexes;i++)
 76         visited[i]=0;//初始化所有顶点都是未访问过
 77     for(int i=0;i<G->numVertexes;i++)
 78         if(!visited[i]) DFS(G,i);
 79     //从adjList[i].data开始进行深度优先递归,若是连通图,只会执行一次DFS(G,0)
 80     //因为深度优先递归后每个visited[i]都是1,不会再执行if了
 81     //若是非连通图,可能会执行到DFS(G,1),DFS(G,2),DFS(G,3),DFS(G,4)
 82 }
 83 
 84 int main(void)
 85 {
 86     GraphAdjList *p=NULL;
 87     p=CreateALGraph(p);
 88     //以下是验证图的创建是否正确
 89     cout<<p->adjList[0].firstedge->adjvex<<endl;//输出3,A的第一个指向是D
 90     cout<<p->adjList[0].firstedge->next->adjvex<<endl;//输出2,A第二个指向是C
 91     cout<<p->adjList[0].firstedge->next->next->adjvex<<endl;//输出1,A的第三个指向是B
 92     cout<<p->adjList[1].firstedge->adjvex<<endl;//输出2,B的第一个指向是C
 93     cout<<p->adjList[1].firstedge->next->adjvex<<endl;//输出0,B第二个指向是A
 94     cout<<p->adjList[2].firstedge->adjvex<<endl;//输出3,C的第一个指向是D
 95     cout<<p->adjList[2].firstedge->next->adjvex<<endl;//输出1,C第二个指向是B
 96     cout<<p->adjList[2].firstedge->next->next->adjvex<<endl;//输出0,C的第三个指向是A
 97     cout<<p->adjList[3].firstedge->adjvex<<endl;//输出2,D的第一个指向是C
 98     cout<<p->adjList[3].firstedge->next->adjvex<<endl;//输出0,D第二个指向是A
 99 
100 //    DFS(p,0);//举个例子,若从下标0开始,执行一次DFS(p,0),输出的遍历顺序是ADCB
101     DFSTraverse(p);//输出的遍历顺序是ADCB
102     return 0;
103 }

1、先理解void DFS(GraphAdjList *G,int i)这个函数,假设从下标2开始,执行一次DFS(p,0),那么遍历结果是ADCB

main函数中用DFS(p,2);把DFSTraverse(p);注释掉。

运行结果:

由于是连通图,执行一次DFS(p,0)即可遍历全部顶点。

2、考虑问题得全面,如果是非连通图,执行一次DFS(G,0),会有顶点没有被遍历到。解决办法是依次执行DFS(G,0),DFS(G,1),DFS(G,2),DFS(G,3),DFS(G,4)即可。用visited[i]对是否访问过该顶点标记,防止不必要的循环。

main函数中用DFSTraverse(p);把DFS(p,0);注释掉。

运行结果同1。

posted @ 2016-04-16 23:38  Pearl_zju  阅读(3908)  评论(1编辑  收藏  举报