伪代码
BFS(G, s):
for each vertex u ∈ G.V - {s}:
u.color = White
u.d = ∞
u.π = NIL
s.color = Gray
s.d = 0
s.π = NIL
Q = ∅
Q.push(s)
while Q ≠ ∅:
u = Q.pop()
for each v ∈ G.Adj[u]:
if v.color == White then
v.color = Gray
v.d = u.d + 1
v.π = u
Q.push(v)
u.color = Black
C++的一般实现方式
第一种写法
首先,我们严格按照伪代码形式来将之写为C++形式。
第一步就是先构造每一个结点,因为结点具有多种属性,因此我们可以使用以下的结构体构造形式。
enum vertexcolor {
WHITE,
GRAY,
BLACK
};
struct vertex {
vertexcolor color;
int d;
int pi;
};
其中我们将结点的颜色color使用一个枚举变量表示。
第二步,构造完毕结点之后,我们还应当构造出图的各种属性,比如图的各个边以及图结点的集合,我们仍然可以用结构体构造出一个图:
struct graph {
vector<vertex> V;
map<vertex *, vector<vertex *> > Adj;
};
在该结构体中,V是图中所有结点的集合,Adj则是一个映射,每给定一个结点的指针,返回一个该结点连接的所有结点的指针的集合。
第三步,在定义了graph这个结构之后,显然我们已经满足了伪代码中所有需要的属性,可以直接利用伪代码执行了。这样一般的结构就是:
void BFS(graph *G, vertex *s) {
const int INF = 0x3f3f3f;
for (vertex u : G->V) {
u.color = WHITE;
u.d = INF;
u.pi = nullptr;
}
s->color = GRAY;
s->d = 0;
//s->pi = nullptr; 此句在上述循环中已经进行过
queue<vertex *> Q;
Q.push(s);
vertex *u;
while (!Q.empty()) {
u = Q.front();
Q.pop();
for (vertex *v : G->Adj[u]) {
if (v->color == WHITE) {
v->color = GRAY;
v->d = u->d + 1;
v->pi = u;
Q.push(v);
}
u->color = BLACK;
}
}
}
这样我们就完成了一个通用性质的c++广度优先算法模板,然而这个模板还不能直接使用,在特定的地方需要作特定的修改。我们以以下这个问题作为例子,来探讨这种写法如何特例化。
迷宫问题
用一个5×5的二维数组表示一个迷宫,其中的1表示墙壁,0表示路,只能横着走或竖着走,不能斜着走,要求输出从左上角到右下角的所需的最小步数。
比如,若输入:
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
则输出:
8
对于这个问题,我们发现我们可以将图设定为只能向右和向下发展,这样我们将图中的每一个结点都将与他右边和下边的结点存在边相连,如果某一个结点上是一堵墙,我们认为他不与任何结点有边相连。因此,我们可以写出以下代码(注释在代码中已给出):