标签:
转载请注明出处http://www.cnblogs.com/hslzju
对《大话数据结构》P241——邻接表的深度优先遍历,进行了自己的理解并完善了代码。
邻接矩阵的深度优先遍历见http://www.cnblogs.com/hslzju/p/5399249.html
举个简单的无序图例子,为了节省时间传手稿。
首先用邻接表的存储结构创建该图,再进行深度优先遍历。代码和解释如下(Qt Creator测试通过):
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。
标签:
原文地址:http://www.cnblogs.com/hslzju/p/5399832.html