输出无向图中从点u到点v的所有路径。这个问题可以通过深度优先搜索(DFS)来解决。
第一步:初始化路径和访问标记
- 设定变量:定义路径数组
path
来存储当前路径,d
为路径的当前长度,visit
数组用来标记节点是否已被访问。 - 初始化路径:将起点
u
添加到路径中,并标记为已访问。
void findpath(AGraph* G, int u, int v, int path[], int d, int visit[]) {
int w, i;
path[++d] = u; // 将当前节点u添加到路径中
visit[u] = 1; // 标记节点u为已访问
第二步:检查是否到达目标节点
- 检查目标:如果当前节点
u
等于目标节点v
,则输出当前路径。 - 输出路径:遍历路径数组,打印出路径中的所有节点。
if (u == v) {
printf("\n");
for (i = 0; i <= d; ++i)
printf("%d ", path[i]);
}
第三步:递归搜索所有可能的路径
- 遍历邻接点:通过邻接表遍历所有与当前节点
u
相邻的节点。 - 递归调用:对每个未访问的邻接点
w
,递归调用findpath
函数继续搜索。
ArcNode* p = G->adjlist[u].firstarc;
while (p != NULL) {
w = p->adjvex;
if (visit[w] == 0)
findpath(G, w, v, path, d, visit);
p = p->nextarc;
}
第四步:回溯
- 取消访问标记:在回溯之前,将当前节点
u
的访问标记重置为未访问,以便其他路径可以重新访问此节点。
visit[u] = 0;
}
完整的代码
void findpath(AGraph* G, int u, int v, int path[], int d, int visit[]) {
int w, i;
path[++d] = u; // 将当前节点u添加到路径中
visit[u] = 1; // 标记节点u为已访问
if (u == v) {
printf("\n");
for (i = 0; i <= d; ++i)
printf("%d ", path[i]);
}
ArcNode* p = G->adjlist[u].firstarc;
while (p != NULL) {
w = p->adjvex;
if (visit[w] == 0)
findpath(G, w, v, path, d, visit);
p = p->nextarc;
}
visit[u] = 0; // 取消访问标记,进行回溯
}
让我们通过一个简单的例子来展示变量在每一步的变化。假设我们有一个无向图,包含四个节点:A, B, C, D,并且有以下边:A-B, A-C, B-D, C-D。我们想要找出从节点A到节点D的所有路径。
图的表示
A -- B -- D
| |
C -- D
变量初始化
path[]
:用来存储路径的数组。d
:路径的当前长度。visit[]
:访问标记数组,用来记录节点是否被访问过。
深度优先搜索过程
步骤 1: 从节点A开始
d = 0
,path[0] = A
,visit[A] = 1
步骤 2: 访问A的邻接点B和C
-
d = 1
,path[1] = B
,visit[B] = 1
-
d = 2
,path[2] = D
,visit[D] = 1
- 此时到达D,输出路径:
A -> B -> D
- 此时到达D,输出路径:
-
回溯到B,
visit[D] = 0
-
d = 1
,path[1] = C
,visit[C] = 1
- 访问C的邻接点D
-
d = 2
,path[2] = D
,visit[D] = 1
- 再次到达D,输出路径:
A -> C -> D
- 再次到达D,输出路径:
-
回溯到C,
visit[D] = 0
-
回溯到A,
visit[C] = 0
,visit[B] = 0
完整的路径输出
A -> B -> D
A -> C -> D
表格:变量变化过程
步骤 | d | path | visit | 当前节点 | 说明 |
---|---|---|---|---|---|
初始化 | 0 | [A] | [1] | A | 从A开始,标记A为已访问 |
访问B | 1 | [A, B] | [1, 1] | B | 访问A的邻接点B |
访问D | 2 | [A, B, D] | [1, 1, 1] | D | 从B访问D,输出路径A->B->D |
回溯 | 1 | [A, B] | [1, 0, 1] | B | 回溯到B,取消D的访问标记 |
访问C | 2 | [A, C] | [1, 0, 1] | C | 访问A的另一个邻接点C |
访问D | 3 | [A, C, D] | [1, 0, 1, 1] | D | 从C访问D,输出路径A->C->D |
回溯 | 2 | [A, C] | [1, 0, 0, 1] | C | 回溯到C,取消D的访问标记 |
回溯 | 1 | [A] | [1, 0, 0] | A | 回溯到A,取消C的访问标记 |
回溯 | 0 | [] | [0, 0, 0] | - | 回溯到起点,取消A的访问标记 |