深度优先搜索算法详解

news/2024/11/28 2:49:36/

深度优先搜索(Depth-First Search,DFS)是一种经典的图形搜索算法,用于在图或树中遍历所有节点。它是一种递归算法,它通过深入到树或图的最深层来遍历节点,并且在回溯时继续搜索其他分支。

深度优先搜索的核心思想是递归和回溯。该算法的基本思路是从根节点开始遍历,深入到树或图的最深层,然后回溯并搜索其他分支。当访问到一个节点时,它会被标记为已访问,然后遍历它的相邻节点。该过程会一直进行,直到找到目标节点或遍历完所有节点。

深度优先搜索可以使用递归或栈实现。在递归实现中,搜索过程通过调用函数来实现,每次递归调用都会将当前节点的相邻节点添加到调用栈中。在栈实现中,搜索过程使用一个栈来存储未访问的节点,并且在访问每个节点时将其弹出并将其相邻节点推入栈中。

下面是一个使用递归实现深度优先搜索的示例代码:

# 定义节点类
class Node:def __init__(self, value):self.value = valueself.visited = Falseself.neighbors = []def add_neighbor(self, node):self.neighbors.append(node)# 定义深度优先搜索函数
def dfs(node):node.visited = Trueprint(node.value)for neighbor in node.neighbors:if not neighbor.visited:dfs(neighbor)# 创建节点并添加邻居
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)node1.add_neighbor(node2)
node1.add_neighbor(node3)
node2.add_neighbor(node4)
node3.add_neighbor(node4)# 调用深度优先搜索函数
dfs(node1)

在上面的示例中,我们首先定义了一个节点类来表示图中的节点。节点包括值、访问标志和相邻节点。然后我们定义了一个深度优先搜索函数dfs,它采用递归方式实现。该函数首先将当前节点标记为已访问并输出其值。然后它遍历节点的相邻节点,如果它们没有被访问过,就递归调用dfs函数来访问它们。

深度优先搜索的应用非常广泛,包括图论、人工智能、自然语言处理等领域。在图论中,深度优先搜索常用于寻找图中的环、连通分量、拓扑排序等问题。在人工智能和自然语言处理中,深度优先搜索被广泛应用于语义分析、机器翻译、语音识别等任务中。

除了递归和栈,深度优先搜索还可以使用迭代加深搜索(Iterative Deepening Depth-First Search,IDDFS)实现。IDDFS是一种迭代算法,它使用深度限制来控制深度优先搜索的深度。它从深度为1的搜索开始,逐步增加搜索深度,直到找到目标节点或搜索完整个图。

下面是一个使用迭代加深搜索实现深度优先搜索的示例代码:

# 定义节点类
class Node:def __init__(self, value):self.value = valueself.visited = Falseself.neighbors = []def add_neighbor(self, node):self.neighbors.append(node)# 定义深度优先搜索函数
def dfs(node, depth, target):if depth == 0 and node.value == target:return Trueif depth > 0:node.visited = Trueprint(node.value)for neighbor in node.neighbors:if not neighbor.visited and dfs(neighbor, depth-1, target):return Truenode.visited = Falsereturn False# 定义迭代加深搜索函数
def iddfs(start, target):depth = 0while True:if dfs(start, depth, target):return Truedepth += 1reset_visited(start)# 重置所有节点的访问标志
def reset_visited(node):node.visited = Falsefor neighbor in node.neighbors:if neighbor.visited:reset_visited(neighbor)# 创建节点并添加邻居
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)node1.add_neighbor(node2)
node1.add_neighbor(node3)
node2.add_neighbor(node4)
node3.add_neighbor(node4)# 调用迭代加深搜索函数
iddfs(node1, 4)

在上面的示例中,我们首先定义了一个节点类来表示图中的节点。然后我们定义了一个深度优先搜索函数dfs和一个迭代加深搜索函数iddfs。dfs函数使用递归方式实现深度优先搜索,而iddfs函数使用深度限制来控制搜索深度,并在搜索完整个图后返回False。

我们还定义了一个辅助函数reset_visited来重置所有节点的访问标志,以便在搜索完整个图后重新开始搜索。

最后,我们创建了一个简单的图,并使用dfs函数来遍历图中的节点。当我们找到目标节点时,dfs函数返回True,并停止搜索。如果搜索完整个图后仍未找到目标节点,则返回False。

下面是一个使用迭代加深搜索算法实现深度优先搜索的示例代码:

# 定义节点类
class Node:def __init__(self, value):self.value = valueself.visited = Falseself.neighbors = []def add_neighbor(self, node):self.neighbors.append(node)# 定义深度优先搜索函数
def dfs(node, target):if node.value == target:return Truenode.visited = Trueprint(node.value)for neighbor in node.neighbors:if not neighbor.visited and dfs(neighbor, target):return Truenode.visited = Falsereturn False# 定义迭代加深搜索函数
def iddfs(root, target):depth = 0while True:if dfs_limit_depth(root, target, depth):return Truedepth += 1# 定义有深度限制的深度优先搜索函数
def dfs_limit_depth(node, target, depth):if depth == 0 and node.value == target:return Trueif depth > 0:node.visited = Truefor neighbor in node.neighbors:if not neighbor.visited and dfs_limit_depth(neighbor, target, depth - 1):return Truenode.visited = Falsereturn False# 创建节点并添加邻居
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)node1.add_neighbor(node2)
node1.add_neighbor(node3)
node2.add_neighbor(node4)
node3.add_neighbor(node4)# 调用迭代加深搜索函数
iddfs(node1, 4)

在上面的示例中,我们首先定义了一个节点类来表示图中的节点。然后我们定义了一个深度优先搜索函数dfs,它使用回溯算法实现深度优先搜索。接着我们定义了一个迭代加深搜索函数iddfs,它使用dfs_limit_depth函数实现有深度限制的深度优先搜索。

我们创建了一个简单的图,并使用iddfs函数来遍历图中的节点。当我们找到目标节点时,iddfs函数返回True,并停止搜索。如果搜索完整个图后仍未找到目标节点,则返回False。

在深度优先搜索中,迭代加深搜索算法是一种非常有用的算法。它可以帮助我们在搜索过程中逐步增加深度限制,并避免在无限深度的情况下陷入死循环。这样可以提高搜索效率,并节省搜索时间和空间。


http://www.ppmy.cn/news/39292.html

相关文章

从SE for AI 到AI for SE,谈无代码平台如何应用AIGC技术

ChatGPT爆⽕全⽹一段时间后,GPT4的发布再次打破普通人的认知。 相比于chatGPT聊天式交互和生成答案,其背后的底层技术AIGC应用场景更加广泛。不管是头部厂商还是个人,都在考虑如何借助这项新技能实现跨越式发展。 数睿数据也在思考无代码开…

半监督学习为什么能work?以及直推式学习是什么

今天在看半监督的时候,突然想起这个问题: 半监督用训好的模型去生成伪标签,再把伪标签当做真标签去训,但是模型能生成伪标签说明模型已经学到了这部分内容,把模型已经学会的内容加进去,让模型继续学&#…

大器晚成我服刘邦,48岁才开始创业

读史使人明智,周末放下手机,静下心来读点人文历史。大器晚成我最佩服刘邦,48岁才开始创业 。在此之前,他是一个出身平凡的农民,早年曾多次失败和受挫。刘邦最后能够战胜项羽,常常让人觉得匪夷所思&#xff…

网络编程三要素

网络编程三要素 IP、端口号、协议 三要素分别代表什么 ip:设备在网络中的地址,是唯一的标识 端口号:应用程序在设备中的唯一标识 协议:数据在网络中传输的规则 常见的协议有UDP、TCP、http、https、ftp ip:IPv4和…

DataGrip连接数据库设置(MySQL、Oracle、SQL Server)

一、DataGrip连接MySQL 1.1 配置信息 1.2 测试查询employees库中departments表信息 employees为测试库,具体来源,参考这篇文章 下载并导入MySQL示例数据库employees 。 1.3 测试查询employees库中employees表信息 二、DataGrip连接Oracle 将SID改为o…

Java中String类型的创建关系、什么是常量池、以及StringBuilder/Buffer等

Java的String字符串使用 String s1 "Hello World";String s2 "Hello World";String s3 new String("Hello World");String s4 new String("Hello World");System.out.println(s1s2); // trueSystem.out.println(s1s3); // falseSy…

线性回归算法

class LR_LS(): def __init__(self): self.w None def fit(self, X, y): # 最小二乘法矩阵求解 # show me your code self.w np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y) # show me your code def predict(self…

重复的子字符串代码随想录刷题 (力扣刷题)

给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/repeated-substring-pattern 为什么会使用KMP 在一个串中查找是否出现过另一个串…