问题
假设图G采用邻接表存储,设计一个算法,求不带权无向连通图G中从顶点u->v的最短路径(路径上经过的顶点数最少。采用广度优先遍历来实现。
基本思路
我们首先来看一下BFS的过程:
图片摘自慕课网李春葆老师讲的数据结构。从图中我们可以看到BFS的过程就是给定一个起点u,从起点u到某一个顶点(假设v)的最短路径构成分层。
下面我先给出一个代码,然后再给出一个例题并进行分析。
代码
typedef struct ANode {
int adjvex; //该边的终点编号
struct ANode *nextarc; //指向下一条边的指针
int name[10]; //该边的权值等信息
}ArcNode;
typedef struct Vnode {
char data; //顶点信息
ArcNode *firstarc; //指向第一条边
}VNode;
typedef struct {
VNode adjlist[MAXV]; //邻接表
int n, e; //途中顶点数n和边数e
}ALGraph;
typedef struct {
int data; //顶点编号
int parent; //前一个顶点的位置
}QUERE;
void ShortPath(ALGraph *G, int u, int v) {
//输出从顶点u到顶点v的最短逆路径
ArcNode *p; int w, i;
QUERE qu[MAXV]; //定义非循环队列
int front = -1, rear = -1; //队列的头、尾指针
int visited[MAXV];
for (i = 0; i < G->n; i++)
visited[i] = 0;
rear++;
qu[rear].data = u;
qu[rear].parent = -1;
visited[u] = 1;
while (front != rear) { //队不空循环
front++;
w = qu[front].data;
if (w == v) {
i = front;
while (qu[i].parent != -1) {
cout << qu[i].data << " ";
i = qu[i].parent;
}
cout << qu[i].data << " " << endl;
break;
}
p = G->adjlist[w].firstarc; //找w的第一个邻接点
while (p != NULL) {
if (visited[p->adjvex] == 0) {
visited[p->adjvex] == 1;
rear++; //将w未访问过的邻接点进队
qu[rear].data = p->adjvex;
qu[rear].parent = front;
}
p = p->nextarc; //找w的下一个邻接点
}
}
}
例题
这里假设起点u=1,终点v=4。要求,求出起点u->v的最短路径。
核心思想
在到达某一点之后遍历这个点所能到达的所有点,并记录能够到达这个点的上一个点。
例题分析
我们可以先画出这个图的邻接表结构:
根据代码我们可以列出三个表来表示运行的过程,各个变量的数值变化:
最左边的这个表表示,图的每个节点是否被访问,visited[i]=1,表示 i 这个节点已经被访问过。从上到下表示了程序运行过程中各个节点被访问的先后顺序。中间的这个表,表示front 和 rear 这两个变量的值随着程序运行而变化的结果。最右边的表表示了,data和parent的这两个变量值的变化。
最终程序输出4-2-1。正好是正确答案的倒序。