图的DFS和BFS
图的遍历是指访问图中的每一个顶点,且只访问一次。最经典的遍历图的方法就是深度优先遍历和广度优先遍历,这两种遍历方法都会产生一个生成树。我们用程序来实现这两种遍历算法的时候,一定要认真分析它们的算法思想以及具体细节,因为遍历图的顶点,每个顶点只能访问一次,所以需要专门设置一个访问标记数组用于标记顶点是否已经被访问过,这样就能避免重复访问了。两种遍历方法从不同的顶点开始遍历,最终得到的结果是不一样的,所以我们要设置一个访问结果数组,用于保存遍历过程中顶点的访问顺序。
对于DFS算法,它的基本思想是:
从图的某一顶点出发开始遍历,将其添加到访问结果数组中,然后设置为已经被访问;
获取该顶点的所有邻接顶点;
然后先访问邻接顶点中的某一个顶点,添加到结果数组,设置已经被访问,
继续获取当前这个顶点的所有邻接顶点;
访问邻接顶点中的某一个顶点,添加到结果数组,设置已经被访问;
……
一直向下递归访问下去,如果没有可再访问的顶点,那么就向上回溯到结果数组中位于当前顶点前面的那个顶点,获取这个顶点的其他邻接顶点,判断是否可以继续向下递归访问,没有的话继续更换邻接顶点,这个顶点的邻接顶点都已经被访问的话,那就继续向上回溯……直到所有顶点被访问完毕。
public class FSGraph extends AbstractGraph<Integer>{ …… public void DFS(int u, int[] parent, List<Integer> searchRes,boolean[] isVisited){ searchRes.add(u); isVisited[u] = true; for (Edge edge : neighbors.get(u)) { if (!isVisited[edge.getV()]){ parent[edge.getV()] = u; DFS(edge.getV(),parent,searchRes,isVisited); } } } }
对于BFS,它的基本思想就是:
从一个顶点出发,访问当前这个顶点的所有邻接顶点,访问完毕后,从某一个邻接顶点出发,访问这个邻接顶点的所有邻接顶点,……,重复上面的动作,直到所有的顶点皆以被访问,这里不用递归,而是借助一个队列。
先将出发顶点存储队列,设置为已被访问,然后出队,获取出队顶点的所有未被访问的邻接顶点,依次将其入队,设置为已被访问。直到队列为空时,遍历结束。
public class FSGraph extends AbstractGraph<Integer>{ …… public void BFS(int v,List<Integer> serachRes){ boolean[] isVisited = new boolean[vertices.size()]; int[] parents = new int[vertices.size()]; Arrays.fill(parents,-1); LinkedList<Integer> queue = new LinkedList<>(); queue.push(v); isVisited[v] = true; while (!queue.isEmpty()){ Integer u = queue.poll(); serachRes.add(u); for (Edge edge : neighbors.get(u)) { if (!isVisited[edge.getV()]){ queue.push(edge.getV()); parents[edge.getV()] = u; isVisited[edge.getV()] = true; } } } } }