对《大话数据结构》P242-243——邻接矩阵的广度优先遍历,进行了自己的理解并完善了代码。
过程如下:先打印,再入队,再出队,再遍历与刚才出队元素相连并没有被访问过的点(入队之前先打印)
1、A入队,A出队,把与A相连并且没有被访问过的顶点B F依次入队
2、B出队,把与B相连并且没有被访问过的顶点C I G依次入队
3、F出队,把与F相连并且没有被访问过的顶点E入队
4、C出队,把与C相连并且没有被访问过的顶点D入队
5、I出队,把与I相连并且没有被访问过的顶点入队,发现没有,不入队
6、G出队,把与G相连并且没有被访问过的顶点H入队
7、E出队,把与E相连并且没有被访问过的顶点入队,发现没有,不入队
8、D出队,把与D相连并且没有被访问过的顶点入队,发现没有,不入队
9、H出队
举个简单的例子:
首先用邻接矩阵的存储结构创建该图,再进行广度优先遍历。
代码和解释如下(VS2012测试通过):
1 #include <iostream>
2 #include <stdlib.h>
3 using namespace std;
4
5 #define MAXVERTEX 6//定义顶点数最多为6
6 #define MAXSIZE 6//循环队列的最大长度定义为6
7
8 //图的邻接矩阵存储结构
9 typedef struct
10 {
11 char vexs[MAXVERTEX];//本例6个顶点
12 int arc[MAXVERTEX][MAXVERTEX];
13 int numVertexes,numEdges;
14 }MGraph;
15
16 //邻接矩阵存储结构的创建
17 MGraph *CreateMGraph(MGraph *G)
18 {
19 G=new MGraph;
20 int i,j,k;
21 cout<<"input numVertexes and numEdges"<<endl;
22 cin>>G->numVertexes>>G->numEdges;//输入6 9,本例6个顶点,9条边
23 cout<<"input numVertexes"<<endl;
24 for(i=0;i<G->numVertexes;i++)
25 cin>>G->vexs[i];//每次循环依次输入A B C D E F
26 for(i=0;i<G->numVertexes;i++)
27 for(j=0;j<G->numVertexes;j++)
28 G->arc[i][j]=0;
29 for(k=0;k<G->numEdges;k++)
30 {
31 cout<<"input vi and vj"<<endl;
32 cin>>i>>j;//每次循环依次输入0 1,0 3,0 5,1 2,1 3,1 5,2 3,3 4,4 5
33 G->arc[i][j]=1;
34 G->arc[j][i]=1;
35 }
36 return G;
37 }
38
39 //循环队列的顺序存储结构
40 //保留一个元素空间,否则front==rear,是空队列还是满队列不容易判断
41 typedef struct
42 {
43 char data[MAXSIZE];//队列,用数组形式表示
44 int front;//头序号,第一个元素的下标
45 int rear;//尾序号,最后一个元素的下标
46 }SqQueue;
47
48 //循环队列的初始化,返回指向循环队列的地址
49 SqQueue *InitQueue(SqQueue *Q)
50 {
51 Q=new SqQueue;
52 Q->front=0;
53 Q->rear=0;//初始化为空队列(front==rear为空队列)
54 return Q;
55 }
56
57 //求循环队列的长度,返回循环队列的当前长度
58 int QueueLength(SqQueue *Q)
59 {
60 return (Q->rear-Q->front+MAXSIZE)%MAXSIZE;
61 }
62
63 //循环队列的入队列操作
64 void EnQueue(SqQueue *Q,char e)
65 {
66 if((Q->rear+1)%MAXSIZE==Q->front)//判断循环队列是否满
67 {
68 cout<<"error"<<" ";
69 return;
70 }
71 Q->data[Q->rear]=e;//将元素e插入队尾
72 Q->rear=(Q->rear+1)%MAXSIZE;//尾序号rear加1,若到最后转向头部
73 cout<<e<<"in"<<" ";
74 return;
75 }
76
77 //循环队列的出队列操作
78 char DeQueue(SqQueue *Q)
79 {
80 char e;
81 if(Q->front==Q->rear)//如果队列是否空
82 {
83 cout<<"error"<<" ";
84 return 0;//返回0表示队列空,没有出队元素
85 }
86 e=Q->data[Q->front];
87 Q->front=(Q->front+1)%MAXSIZE;//头序号front加1,若到最后转向头部
88 cout<<e<<"out"<<" ";
89 return e;
90 }
91
92 //邻接矩阵的广度遍历
93 void BFSTraverse(MGraph *G)
94 {
95 int visited[MAXVERTEX];//标志顶点是否被访问,0是未被访问过,1是被访问过
96 char e;
97
98 SqQueue *s=NULL;
99 s=InitQueue(s);//初始化一个循环队列s,最大长度为MAXSIZE=6,初始为空
100
101 for(int i=0;i<G->numVertexes;i++)//初始化所有顶点都未被访问过
102 visited[i]=0;
103
104 for(int i=0;i<G->numVertexes;i++)//对于连通图,执行一次就可以遍历所有顶点
105 {
106 if(!visited[i])//如果没有被访问过,就处理,防止不必要的重复处理
107 {
108 visited[i]=1;//设置当前顶点访问过
109 cout<<"print1"<<G->vexs[i]<<" ";//打印该顶点
110 EnQueue(s,G->vexs[i]);//把该顶点入队
111 while(QueueLength(s))//若当前队列长度不等于0(即不为空)
112 {
113 e=DeQueue(s);//元素出队,需要知道出队元素的下标,更新i
114 switch (e)
115 {
116 case 'A':i=0;break;
117 case 'B':i=1;break;
118 case 'C':i=2;break;
119 case 'D':i=3;break;
120 case 'E':i=4;break;
121 case 'F':i=5;break;
122 default:break;
123 }
124 cout<<endl;
125 //for循环寻找与刚才出队的顶点相连的并没有被访问过的顶点,如果找到该顶点,马上打印,并把找到的顶点入队
126 for(int j=0;j<G->numVertexes;j++)//判断vexs[i]与其它顶点(包括自身)是否相连
127 {
128 if(G->arc[i][j]==1&&!visited[j])//如果与vexs[i]相连的顶点没有被访问过
129 {
130 visited[j]=1;//把找到的顶点设置为访问过
131 cout<<"print2"<<G->vexs[j]<<" ";//打印该找到的顶点
132 EnQueue(s,G->vexs[j]);//把找到的顶点入队
133 }
134 }
135 }
136 }
137 }
138 }
139
140 int main(void)
141 {
142 MGraph *p=NULL;
143 p=CreateMGraph(p);//创建图
144 BFSTraverse(p);//广度遍历
145 }
运行结果:
结果解释:
print1和print2用来标记在函数哪个部分打印,可以看出遍历顺序是ABDFCE。
也可以看出入队和出队的顺序。
打印A,A入队,A出队。
打印B,B入队;打印D,D入队;打印F,F入队。B出队。
打印C,C入队。D出队。
打印E,E入队。F出队。
C出队。
E出队。