Java数据结构与算法之DFS
深度优先搜索算法
- 深度优先遍历,从初始访问结点出发,初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点,可以这样理解:每次都在访问完当前结点后首先访问当前结点的第一个邻接结点。
- 我们可以看到,这样的访问策略是优先往纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问。
- 显然,深度优先搜索是一个递归的过程。
算法分析:
- 假设起始节点为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;
}
实现结果:
这里的结果与分析的结果有所出入,这是因为分析中借用了树的概念,在实现中需要左右子树递归。而这里则运用了上一节图中邻接矩阵的概念,将边用二维矩阵的形式表示出来,故搜索顺序会有些出入。
但所用的思想是一致的:一条路走到黑,再回头。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现