一、算法思想
对于图的深度优先遍历和树的深度优先遍历相似。不同之处在于,在图中可能出现环。所以,如果将树的深度优先遍历算法放到包含环的图中就会造成死循环。因此,需要引入标志位数组用来记录已经遍历过的节点,当已访问过的节点再次出现的时候就跳过。深度优先遍历的主要思想是递归,不断递归当前节点的邻居节点。
对于图的广度优先遍历,同样需要使用标志位数组用来记录已访问的节点,与深度优先遍历不同,广度优先遍历通过使用队列来代替递归。
二、JAVA实现
深度优先遍历:
public class DepthFirstSearchPath {
private boolean[] marked;//标记访问数组
private int[] edgeTo;//标记节点的前位节点
private int s;
public DepthFirstSearchPath(UndirGraph graph,int s){
marked=new boolean[graph.V];
this.s=s;
edgeTo=new int[graph.V];
dfs(graph,s);
}
public void dfs(UndirGraph graph,int s){
marked[s]=true;
for (int i:graph.adj(s)){
if (!marked[i]){
edgeTo[s]=i;
dfs(graph,i);
}
}
}
public boolean hasPathto(int s){
return marked[s];
}
public Iterable<Integer> Pathto(int v){
if (!hasPathto(v))
return null;
Stack<Integer> stack=new Stack<>();
for (int i=v;i!=s;i=edgeTo[i]){
stack.push(i);
}
stack.push(s);
return stack;
}
}
广度优先遍历
public class BreadthFirstSearchPath {
boolean[] marked;//存储被访问过的节点
private int s;//存储查询路径的起点
int[] edgeTo;//存储该节点的前置节点
public BreadthFirstSearchPath(UndirGraph graph,int s){
this.s=s;
marked=new boolean[graph.V];
edgeTo=new int[graph.V];
bfs(graph,s);
}
public void bfs(UndirGraph graph,int s){
Queue<Integer> queue=new LinkedList<>();
queue.offer(s);//将节点加入队列
marked[s]=true;//将节点设置为已经访问
while (!queue.isEmpty()){
int temp=queue.poll();//将队头元素取出
for (int i:graph.adj(temp)){
if (!marked[i]){
marked[i]=true;
edgeTo[i]=temp;
queue.offer(i);
}
}
}
}
public boolean hasPath(int v){
return marked[v];
}
public Iterable<Integer> Pathto(int v){
Stack<Integer> stack=new Stack<>();
if (!hasPath(v))
return null;
for (int i=v;i!=s;i=edgeTo[i]){
stack.push(i);
}
stack.push(s);
return stack;
}
}