图的深度优先遍历是从初始顶点出发,找到是否有邻接点,判断是否访问过,如果没有访问过访问该邻接点,如果邻接点还有邻接点就继续访问,直到到达没有邻接点可以访问的顶点,就回退到上一个顶点。 深度优先遍历可以想象成走迷宫,一直路过各个顶点,直到没有路了,再回退到上个顶点继续走。因此是递归思想。可以用方法(method)递归和栈(stack)递归两种方式实现。
接口Paths是抽象出遍历路径的类。
public class DepthFirstSearch implements Paths{ //标记是否被访问列表 private boolean[] marked; //访问的次数 private int count; private int[] edgeTo;//源顶点,用来记录寻找路径 private int start; /** * * @param graph 图对象 * @param start 开始的节点 */ public DepthFirstSearch(UndirectedGraph graph,int start){ //通过顶点数创建访问列表 marked = new boolean[graph.vertexNum()]; this.start = start; edgeTo = new int[graph.vertexNum()]; dfsForStack(graph, start); } /** * 深度遍历图方法,递归 * @param graph 图对象 * @param vertex 顶点下标 */ private void dfs(UndirectedGraph graph,int vertex){ //将顶点标记为已经被访问 marked[vertex] = true; //访问顶点 System.out.println(vertex); count++; //获取顶点邻接的顶点 Iterable<Integer> adj = graph.adj(vertex); //访问邻接的顶点 for (Integer integer : adj) { //如果顶点没有被访问过,就递归的访问 if(!marked[integer]){ //记录顶点被访问的源路径,因为每个顶点的源被访问一次,所以只会有一个源路径 edgeTo[integer] = vertex; dfs(graph,integer); } } } /** * 非递归,栈实现 * @param graph * @param vertex */ private void dfsForStack(UndirectedGraph graph,int vertex){ Stack<Integer> stack = new Stack<>(); stack.push(vertex); while(!stack.isEmpty()){ vertex = stack.peek(); //如果没被访问过,就访问 if(!marked[vertex]){ marked[vertex] = true; System.out.println(vertex); //然后再继续访邻接顶点 Iterable<Integer> adj = graph.adj(vertex); for (Integer integer : adj) { //访问没有被访问的邻接顶点 if(!marked[integer]){ //将邻接顶点入栈,如果栈中存在,就置顶 if(stack.contains(integer)){ //移除然后在添加就置顶了 stack.removeElement(integer); } //记录顶点的源顶点 edgeTo[integer] = vertex; stack.push(integer); } } }else{ //访问过就弹出 stack.pop(); } } } /** * 是否包含到v的路径 */ @Override public boolean hasPathTo(int v) { //该顶点是否被访问过 return marked[v]; } /** * 找到起始顶点到指定顶点(v)的一条路径 */ @Override public Iterable<Integer> pathTo(int v) { if(!hasPathTo(v)){ return null; } Stack<Integer> path = new Stack<>(); //从路径的顶点,递归回到开始的节点 for(int m = v;m != start ;m = edgeTo[m]){ path.push(m); } path.push(start); return path; } }paths接口
/** * 路径接口 * @author yuli * */ public interface Paths { /** * 是否包含到v的路径 * @param v * @return */ boolean hasPathTo(int v); /** * 返回到v经过的路径 * @param v * @return */ Iterable<Integer> pathTo(int v); }