深度优先遍历(Depth-First-Search)深度优先遍历有点像二叉数的遍历就是一条路走到黑。
算法思想
假设我们以v0为顶点遍历整张图,首先我们把v0入栈检查v0是否与其他边先相连如果没有就直接返回。显然这张图v0有2条边分别对应这v2与v3把v3v2入栈现在v2在栈顶取出v2发现v2只有一条边就是对应着v0这个点,v0入栈v2出栈继续重复然后无限循环下去这显然不是我们要的结果所以我们给每个顶点设置个标记来代表已访问。现在返回到v0发现v0已访问就不访问v0了直接访问v3可能这里大家有点不明白,v0本来是在栈底,v0就算不设置标记v2返回依旧会访问到v0,这样想是多虑了这个是出栈时的顺序如果设置标记v0v2就会重复入栈,就是有可能有n个v0v2然后栈溢出。回归主题现在到了v3然后v3发现只有一个顶点就是v1v1入栈v1继续发现没有全部以访问就开始按顺序出栈了。v1-v3-v0依次出来v2去那里了v2在开始的访问v2的时候发现没有了为标记的顶点就已经出栈了。
因为递归的好理解所以先写递归的
public class Graph {
private int vertexSize;//顶点数
private int[][] map ;//图
private ArrayList<String> vertex;//顶点描述信息
private boolean[] isVisited;//顶点标记
public Graph(int vertexSize){
//设置顶点
this.vertexSize = vertexSize;
map = new int[vertexSize][vertexSize];
vertex = new ArrayList<>();
isVisited = new boolean[vertexSize];
}
public void addVertex(String v){
vertex.add(v);
}
public void insertEdgs(int v1,int v2,int weight){
//设置相连的顶点
map[v1][v2] = weight;
map[v2][v1] = weight;
}
public void depthFirstSearch(int n){
isVisited[n] = true;//进来就直接标记以访问
System.out.print(vertex.get(n)+"-");//输出顶点信息
for(int i = 0; i < vertexSize;i++){
//遍历所有与n顶点相连的顶点
if(!isVisited[i]&&map[n][i] == 1){
depthFirstSearch(i);//发现下一个未标记顶点开始递归
}
}
}
public void depthFirstSearch(){
for(int i = 0 ; i<vertexSize;i++){
isVisited[i] = false;//初始化标记
}
/**
* 遍历所有顶点
*/
for(int i = 0 ; i <vertexSize ; i++){
if (!isVisited[i]) {
//如果为访问就开始遍历与之相连的顶点
depthFirstSearch(i);
}
}
}
public static void main(String[] args) {
String[] vertex = {"V0","V1","V2","V3"};
Graph graph = new Graph(vertex.length);
for(String string:vertex){
graph.addVertex(string);
}
graph.insertEdgs(0,2,1);
graph.insertEdgs(0,3,1);
graph.insertEdgs(1,3,1);
graph.depthFirstSearch();
}
}
输出的顺序V0-V2-V3-V1-是不是和上面分析的一样。
好了递归实现了递归现在实现非递归的,这里原谅我偷个懒重复的代码就不写了直接写非递归的代码。
public void depthFirstSearch(){
for(int i = 0 ; i<vertexSize;i++){
isVisited[i] = false;
}//初始化标记
Stack<Integer> stack = new Stack<>();
stack.push(0);
int i = 0;
System.out.print(vertex.get(0)+"-");
boolean flag = false;
while(!stack.empty()){
int k = stack.peek();//查看栈顶的元素
isVisited[k] = true;//设置为以访问
flag = false;
i = 0;
for(;i<vertexSize;i++){
if(!isVisited[i]&&map[k][i] == 1){
stack.push(i);
System.out.print(vertex.get(i)+"-");//入栈就输出
flag = true;//如果有与之相连的顶点就设置true
}
}
if(!flag){
//没有一个与之相连的未被访问的顶点就出栈
stack.pop();
}
}
}
输出代码依旧时V0-V2-V3-V1-