携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
深度优先搜索
深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。
深度优先遍历(DFS):从一个顶点开始,沿着一条路径一直搜索,直到到达该路径的最后一个结点,然后回退到之前经过但未搜索过的路径继续搜索,直到所有路径和结点都被搜索完毕
DFS与二叉树的先序遍历类似,可以采用递归或者栈的方式实现
算法思想:回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
执行步骤:
- 1、从 1 出发,路径为:
1 -> 2 -> 3 -> 6 -> 9 -> 8 -> 5 -> 4 - 2、当搜索到 4 时,相邻没有发现未被访问的点,此时我们要往后倒退,找寻别的没搜索过的路径
- 3、退回到 5 ,相邻没有发现未被访问的点,继续后退
- 4、退回到 8 ,相邻发现未被访问的点 7,路径为:
8 -> 7 - 5、当搜索到 7 ,相邻没有发现未被访问的点,,此时我们要往后倒退...
- 6、退回路径
7 -> 8 -> 9 -> 6 -> 3 -> 2 -> 1,流程结束
代码实现:
- 栈类
public class MyStack {
//栈的底层使用数组来存储数据
//private int[] elements;
int[] elements; //测试时使用
public MyStack() {
elements = new int[0];
}
//添加元素
public void push(int element) {
//创建一个新的数组
int[] newArr = new int[elements.length + 1];
//把原数组中的元素复制到新数组中
for (int i = 0; i < elements.length; i++) {
newArr[i] = elements[i];
}
//把添加的元素放入新数组中
newArr[elements.length] = element;
//使用新数组替换旧数组
elements = newArr;
}
//取出栈顶元素
public int pop() {
//当栈中没有元素
if (is_empty()) {
throw new RuntimeException("栈空");
}
//取出数组的最后一个元素
int element = elements[elements.length - 1];
//创建一个新数组
int[] newArr = new int[elements.length - 1];
//原数组中除了最后一个元素其他元素放入新数组
for (int i = 0; i < elements.length - 1; i++) {
newArr[i] = elements[i];
}
elements = newArr;
return element;
}
//查看栈顶元素
public int peek() {
return elements[elements.length - 1];
}
//判断栈是否为空
public boolean is_empty() {
return elements.length == 0;
}
//查看栈的元素个数
public int size() {
return elements.length;
}
}
- 顶点类
public class Vertex {
private String value;
public boolean visited; //访问状态
public Vertex(String value) {
super();
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
- 图类
import mystack.MyStack;
public class Graph {
private Vertex[] vertex; //顶点数组
private int currentSize; //默认顶点位置
public int[][] adjMat; //邻接表
private MyStack stack = new MyStack(); //栈
private int currentIndex; //当前遍历的下标
public Graph(int size) {
vertex = new Vertex[size];
adjMat = new int[size][size];
}
//向图中加入顶点
public void addVertex(Vertex v) {
vertex[currentSize++] = v;
}
//添加边
public void addEdge(String v1, String v2) {
//找出两个点的下标
int index1 = 0;
for (int i = 0; i < vertex.length; i++) {
if (vertex[i].getValue().equals(v1)) {
index1 = i;
break;
}
}
int index2 = 0;
for (int i = 0; i < vertex.length; i++) {
if (vertex[i].getValue().equals(v2)) {
index2 = i;
break;
}
}
//表示两个点互通
adjMat[index1][index2] = 1;
adjMat[index2][index1] = 1;
}
//深度优先搜索
public void dfs() {
//把第0个顶点标记为已访问状态
vertex[0].visited = true;
//把第0个的下标放入栈中
stack.push(0);
//打印顶点值
System.out.println(vertex[0].getValue());
//遍历
out:
while (!stack.is_empty()) {
for (int i = currentIndex + 1; i < vertex.length; i++) {
//如果和下一个遍历的元素是通的
if (adjMat[currentIndex][i] == 1 && vertex[i].visited == false) {
//把下一个元素压入栈中
stack.push(i);
vertex[i].visited = true;
System.out.println(vertex[i].getValue());
continue out;
}
}
//弹出栈顶元素(往后退)
stack.pop();
//修改当前位置为栈顶元素的位置
if (!stack.is_empty()) {
currentIndex = stack.peek();
}
}
}
}