深度优先搜索算法
- 深度优先遍历,从初始访问结点出发,初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点,可以这样理解:每次都在访问完当前结点后首先访问当前结点的第一个邻接结点。
- 我们可以看到,这样的访问策略是优先往纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问。
- 显然,深度优先搜索是一个递归的过程。
算法分析:
- 假设起始节点为1;先搜索1节点的右侧邻接节点为2,此时将1节点置为已搜索状态;判断2节点是否为已搜索状态,若未搜索,则将2节点置为已搜索状态;每次都优先搜索判断右侧邻接节点;
- 如图所示,若此时已搜索至5节点,发现右侧邻接节点为2且已处于已搜索状态;故递归至上一个节点8搜索左侧邻接节点处...层层递归判断至1节点(在图中没有并表明递归路径);
- 此时搜索判断1节点的左侧邻接节点3不为已搜索状态,故继续进行先右侧后左侧邻接节点搜索判断操作;
- 直至最后一个节点6搜索判断3节点为已搜索状态,故递归至最初的1节点;判断结束,搜索结束。
代码实现:
// 对dfs进行一个重载,遍历我们所有的结点,并进行dfs
public List<Integer> DFS() {
isSreachs = new boolean[vertexList.size()];
dfsArrays = new ArrayList<>();
for (int i = 0; i < vertexList.size(); i++) {
// 遍历所有的结点,进行dfs[回溯]
if (!isSreachs[i]) {
dfsArrays = DFS(isSreachs[i], i);
}
}
return dfsArrays;
}
public List<Integer> DFS(boolean isSreach, int i) {
// 首先我们将该节点添加进数组
dfsArrays.add(showVertexList(i));
// 将节点设置为已经访问
isSreachs[i] = true;
// 查找节点i的第一个邻接节点w
int w = getFirstNeighbor(i);
while (w != -1) { // 说明存在w
if (!isSreachs[w]) {
DFS(isSreachs[w],w);
}
// w节点已经被访问过
w = getNextNeightbor(i,w);
}
return dfsArrays;
}
// 得到第一个邻接结点的下标
public int getFirstNeighbor(int index) {
for (int j = 0; j < vertexList.size(); j++) {
if (edges[index][j] == 1) {
return j;
}
}
return -1;
}
// 根据前一个邻接结点的下标来获取下一个邻接结点
public int getNextNeightbor(int v1, int v2) {
for (int i = v2+1; i < vertexList.size(); i++) {
if (edges[v1][i] == 1) {
return i;
}
}
return -1;
}
实现结果:
这里的结果与分析的结果有所出入,这是因为分析中借用了树的概念,在实现中需要左右子树递归。而这里则运用了上一节图中邻接矩阵的概念,将边用二维矩阵的形式表示出来,故搜索顺序会有些出入。
但所用的思想是一致的:一条路走到黑,再回头。