所谓深度优先搜索,是从"图"中的一个顶点出发,每次遍历当前访问顶点的临界点,一直到访问的顶点没有未被访问过的临界点为止。然后采用依次回退的方式,查看来的路上每一个顶点是否有其它未被访问的临界点。访问完成后,判断图中的顶点是否已经全部遍历完成,如果没有,以未访问的顶点为起始点,重复上述过程。(百度)
(不了解图的可以先看看这篇文章)
深度优先搜索(DFS) (深度优先搜索通过栈来实现)
注:深度优先搜索(DFS)是图搜索方法的一种
规则如下:
规则1:如果可能,访问一个邻接的未访问顶点,标记它,并将它放入栈中。
规则2:当不能执行规则 1 时,如果栈不为空,就从栈中弹出一个顶点。
规则3:如果不能执行规则 1 和规则 2 时,就完成了整个搜索过程。
对于上图,应用深度优先搜索如下:
假设选取 A 顶点为起始点,并且按照字母优先顺序进行访问,
那么应用规则 1 ,接下来访问顶点 B,然后标记它,并将它放入栈中;
再次应用规则 1,接下来访问顶点 F,
再次应用规则 1,访问顶点 H。
我们这时候发现,没有 H 顶点的邻接点了,这时候应用规则 2,
从栈中弹出 H,这时候回到了顶点 F,
但是我们发现 F 也除了 H 也没有与之邻接且未访问的顶点了,那么再弹出 F,这时候
回到顶点 B,
同理规则 1 应用不了,应用规则 2,弹出 B,
这时候栈中只有顶点 A了,然后 A 还有未访问的邻接点,所有接下来访问顶点 C,
但是 C又是这条线的终点,所以从栈中弹出它,再次回到 A,
接着访问 D,G,I,
最后也回到了 A,然后访问 E,但是最后又回到了顶点 A,
这时候我们发现 A没有未访问的邻接点了,所以也把它弹出栈。
现在栈中已无顶点,于是应用规则 3,完成了整个搜索过程。
深度优先搜索在于能够找到与某一顶点邻接且没有访问过的顶点。
实现深度优先搜索的栈
package cn.learn.datastructure.graph;
/**
* @author 阿康
* 实现深度优先搜索的栈StackX
*/
public class StackX {
/**
* size 定义长度
* st 栈实现数组
* top 栈顶指针
*/
final int size = 20;
int[] st;
int top;
public StackX() {
this.st = new int[size];
top = -1;
}
public void push(int data){
st[++top] = data;
}
public int pop() {
return st[top--];
}
/**
* 查看栈顶元素
*/
public int peek() {
return st[top];
}
public boolean isEmpty() {
return top == -1;
}
}
在图中实现深度优先搜索
Java代码实现(可运行) , 需要添加上StackX类
package com.example.demo.datastructure.graph;
/**
* @author sk143
* 封装图实现
*/
public class Graph {
/**顶点个数*/
final int MAX_VERT = 20;
/**顶点数组*/
private Vertex[] vertexList;
/**邻接矩阵储存"边"数组元素0表示无边界,数组1表示有边界*/
private int[][] adjMat;
/**顶点个数*/
private int nVert;
/**使用栈实现深度优先搜索*/
private Stack theStack;
/**
* 图结构初始化
*/
public Graph() {
// 定点列表
vertexList = new Vertex[MAX_VERT];
// 邻接矩阵
adjMat = new int[MAX_VERT][MAX_VERT];
// 顶点个数
nVert = 0;
// 初始化邻接矩阵元素都为 0,即所有定点都没边
for (int i = 0; i < MAX_VERT; i++) {
for (int j = 0; j < MAX_VERT; j++) {
adjMat[i][j] = 0;
}
}
theStack = new Stack();
//theQueue = new Queue();
}
/**
* 添加顶点到数组中
*/
public void insert(char label) {
vertexList[nVert++] = new Vertex(label);
}
/**
* 邻接矩阵表示边是对称的,两部分都要赋值
*/
public void addEdge(int start, int end) {
adjMat[start][end] = 1;
adjMat[end][start] = 1;
}
/**
* 打印某个顶点的值
*/
public void disPlayVertex(int v) {
System.out.print(vertexList[v].label);
}
/**
* 深度优先搜索法:
* 1.用peek()方法检查栈顶的顶点
* 2.用getAdjUnvisitedVertex()方法找到当前栈顶点邻接且未被访问的顶点
* 3.第二部方法返回值不等于-1,则找到下一个未访问的邻接顶点,访问这个顶点,
* 并入栈,返回-1则没有找到,出栈
*/
public void depthFirstSearch() {
// 从第一个顶点开始访问
// 访问后标记未true
vertexList[0].isVisited = true;
// disPlayVertex(0);
// 将第一个顶点放到栈中
theStack.push(0);
while (!theStack.isEmpty()) {
// 找到未访问的邻接点
int current = theStack.peek();
int v = getAdjUnvisitedVertex(current);
if (v == -1) {
// 如果当前顶点为-1,表示没有邻接且未被访问出顶点
theStack.pop();
} else {
vertexList[v].isVisited = true;
disPlayVertex(current);
disPlayVertex(v);
System.out.println(" ");
theStack.push(v);
}
}
// 栈访问完毕,重置所有标记位置isVisited = false;
for (int i = 0; i < nVert; i++) {
vertexList[i].isVisited = false;
}
}
/**
* 找到与某一顶点邻接且未被访问的顶点
*/
private int getAdjUnvisitedVertex(int v) {
for (int i = 0; i < nVert; i++) {
if (adjMat[v][i] == 1 && !vertexList[i].isVisited) {
return i;
}
}
return -1;
}
public static void main(String[] args) {
Graph graph = new Graph();
graph.insert('A');
graph.insert('B');
graph.insert('C');
graph.insert('D');
graph.insert('E');
graph.addEdge(0, 1); // AB
graph.addEdge(1, 2); // BC
graph.addEdge(0, 3); // AD
graph.addEdge(0, 4); // DE
System.out.println();
graph.depthFirstSearch();// ABCDE
System.out.println("-----------");
}
}
运行结果如下
AB
BC
AD
AE
-----------
(转载请标明出处)