Project 1
实验题目
设计并实现求两点间所有路径的算法。
程序设计
DFS算法
- 深度优先遍历:
深度优先搜索(Depth_First Search)遍历类似于树的先根遍历,是树的先根遍历的推广。
假设给定图G,图中所有顶点未曾被访问过,则深度优先搜索可以从图中某个顶点v出发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。这是一个递归的过程。 - 深度优先遍历的过程
假设给定图G,设x 是当前被访问顶点, 在对x 做过访问标记后, 选择一条从x出发的未检测过的边(x,y)。若发现顶点y 已访问过,则重新选择另一条从x 出发的未检测过的边,否则若顶点y未被访问过,沿边(x,y)到达未曾访问过的y,对y访问并将其标记为已访问过;然后从y开始搜索,直到搜索完从y 出发的所有路径,即访问完所有从y 出发可达的顶点之后,才回溯到顶点x,并且再选择一条从x 出发的未检测过的边。上述过程直至从x 出发的所有边都已检测过为止。此时,若x 不是源点,则回溯到在x 之前被访问过的顶点;否则图中所有和源点有路径相通的顶点(即从源点可达的所有顶点)都已被访问过,若图G 是连通图,则遍历过程结束,否则继续选择一个尚未被访问的顶点作为新源点,进行新的搜索过程。
表存储结构:邻接表
运用DFS查找两点间所有路径的算法思想:
- 查找:从起始的城市对应的顶点开始,逐次访问其邻接顶点。访问一个顶点时,标记为1,将其存入数组中。如果被访问的点在其此次所在的路径中之前已被访问(包括此次访问到的是起始顶点)或该顶点没有邻接顶点了且该顶点不是目的顶点,就不再继续访问其邻接顶点,此条路径不再继续。 如果该顶点是目的顶点,则将该条路径上之前访问的包括此次访问的顶点全部输出,显示所找到的一条简单路径。之后将上一个顶点置为0观察是否还有其余临点,如果有继续查找,如果没有则返回上一个顶点置为0,继续深度优先思想查找。
程序代码
/ **
*@author ZhangManyuan
*/
import java.util.List;
import java.util.ArrayList;
public class DepthFirstSearch {
private static void dfs_rec(ArrayList<ArrayList<Integer>> adjLists, boolean[] visited, int v, int d,
List<Integer> path) {
visited[v] = true;
path.add(v);
if (v == d) {
for (int i = 0; i < path.size(); i++) {
System.out.print(path.get(i));
}
System.out.println("");
}
else {
for (int w : adjLists.get(v)) {
if (!visited[w]) {
dfs_rec(adjLists, visited, w, d, path);
}
}
}
path.remove(path.size() - 1);
visited[v] = false;
}
public static void dfs(ArrayList<ArrayList<Integer>> adjLists, int s, int d) {
int n = adjLists.size();
boolean[] visited = new boolean[n];
List<Integer> path = new ArrayList<Integer>();
int path_index = 0;
dfs_rec(adjLists, visited, s, d, path);
}
public static void main(String[] args) {
ArrayList<ArrayList<Integer>> adjLists = new ArrayList<ArrayList<Integer>>();
final int n = 8;
for (int v = 0; v < n; v++) {
adjLists.add(new ArrayList<Integer>());
}
adjLists.get(0).add(1);
adjLists.get(0).add(2);
// ---------
adjLists.get(1).add(0);
adjLists.get(1).add(3);
adjLists.get(1).add(4);
// ---------
adjLists.get(2).add(0);
adjLists.get(2).add(5);
adjLists.get(2).add(6);
// ---------
adjLists.get(3).add(1);
adjLists.get(3).add(7);
// ---------
adjLists.get(4).add(1);
adjLists.get(4).add(7);
// ---------
adjLists.get(5).add(2);
adjLists.get(5).add(6);
// ---------
adjLists.get(6).add(2);
adjLists.get(6).add(5);
// ---------
adjLists.get(7).add(3);
adjLists.get(7).add(4);
dfs(adjLists, 3, 6);
}
}
程序测试
创建邻接表的过程:(往ArrayList<ArrayList<Integer>> adjLists
中不断添加结构)
adjLists.get(0).add(1);
adjLists.get(0).add(2);
// ---------
adjLists.get(1).add(0);
adjLists.get(1).add(3);
adjLists.get(1).add(4);
// ---------
adjLists.get(2).add(0);
adjLists.get(2).add(5);
adjLists.get(2).add(6);
// ---------
adjLists.get(3).add(1);
adjLists.get(3).add(7);
// ---------
adjLists.get(4).add(1);
adjLists.get(4).add(7);
// ---------
adjLists.get(5).add(2);
adjLists.get(5).add(6);
// ---------
adjLists.get(6).add(2);
adjLists.get(6).add(5);
// ---------
adjLists.get(7).add(3);
adjLists.get(7).add(4);
在这里我们输出3到6之间的所有路径 dfs(adjLists, 3, 6);
实际运行结果
实验中产生的问题
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 7, Size: 7
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at DepthFirstSearch.main(DepthFirstSearch.java:65)
- 解决方法:
显示为ArrayList的角标溢出
解决办法:经过检查,发现时节点数目输错,致使adjLists.get(7).add(3)
出现错误
总结
- DFS为遍历图的优秀算法,巧妙利用递归,再加上flag标记,就可以完成寻找两点间所有路径的算法
- 编程技巧有待提高