深度优先学习是一种在树形结构的数据中进行遍历和问题求解的方法,它以递归的形式从根节点开始,沿着一条路径尽可能深地向下搜索,直到该路径的末端。然后回溯到最近的祖先节点,继续沿着其他路径进行深度搜索,这种方法以其递归性质和“先深入后回溯”的策略而闻名。
深度优先学习简介深度优先搜索(Depth-First Search, DFS)是一种用于遍历或搜索树或图的算法。它从给出的树的根节点开始,然后遍历根节点的孩子节点。然后选择一个孩子节点,继续遍历其孩子节点。如果在任一节点处没有子节点,那么在回溯到其父节点后,选择另一个子节点进行遍历。该过程一直持续到遍历完所有节点。
递归:DFS通常采用递归方式实现,递归是一种函数调用自身的技术。在DFS中,递归用于处理子节点。
栈:当使用非递归实现DFS时,需要使用栈来存储节点信息。每次访问一个节点时,将该节点的子节点压入栈中。
回溯:在一条路径穷尽后,算法返回到上一个节点继续寻找其他路径。
深度优先学习的优势和应用场景深度优先搜索的基本步骤如下:
我们以Python为例,实现一个简单的深度优先搜索算法来遍历一棵二叉树。
class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def dfs(root): if root is None: return print(root.val) # 处理当前节点 dfs(root.left) # 递归处理左子树 dfs(root.right) # 递归处理右子树 # 创建一个简单的二叉树 root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.left.right = TreeNode(5) # 调用深度优先搜索函数 dfs(root)
上述代码创建了一个简单的二叉树,并调用dfs
函数来遍历它。输出结果是:1, 2, 4, 5, 3。
假设我们有一个迷宫,用一个二维数组表示,其中1代表墙,0代表路径。我们需要找到从起点到终点的路径。
def dfs(maze, start, end, path=[]): if start == end: print("Path found:", path) return True if start[0] < 0 or start[0] >= len(maze) or start[1] < 0 or start[1] >= len(maze[0]) or maze[start[0]][start[1]] != 0: return False maze[start[0]][start[1]] = 2 # Mark the cell as visited path.append(start) if dfs(maze, (start[0]-1, start[1]), end, path) or \ dfs(maze, (start[0]+1, start[1]), end, path) or \ dfs(maze, (start[0], start[1]-1), end, path) or \ dfs(maze, (start[0], start[1]+1), end, path): return True path.pop() # Backtrack maze[start[0]][start[1]] = 0 # Unmark the cell return False # Example usage maze = [[0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 0]] start = (0, 0) end = (4, 4) dfs(maze, start, end)
def dfs_with_visited(maze, start, end, visited=None): if visited is None: visited = set() if start == end: print("Path found:", list(visited)) return True if start in visited: return False if start[0] < 0 or start[0] >= len(maze) or start[1] < 0 or start[1] >= len(maze[0]) or maze[start[0]][start[1]] != 0: return False visited.add(start) # Mark the cell as visited if dfs_with_visited(maze, (start[0]-1, start[1]), end, visited) or \ dfs_with_visited(maze, (start[0]+1, start[1]), end, visited) or \ dfs_with_visited(maze, (start[0], start[1]-1), end, visited) or \ dfs_with_visited(maze, (start[0], start[1]+1), end, visited): return True visited.remove(start) # Backtrack return False # 使用带有访问标记的DFS dfs_with_visited(maze, start, end)
def dfs_with_stack(maze, start, end): if start == end: print("Path found:", []) return True stack = [start] visited = set() while stack: current = stack.pop() if current in visited: continue if current == end: print("Path found:", list(visited)) return True visited.add(current) maze[current[0]][current[1]] = 2 # Mark the cell as visited for move in [(0, 1), (0, -1), (1, 0), (-1, 0)]: next_pos = (current[0] + move[0], current[1] + move[1]) if next_pos[0] >= 0 and next_pos[0] < len(maze) and next_pos[1] >= 0 and next_pos[1] < len(maze[0]) and maze[next_pos[0]][next_pos[1]] == 0: stack.append(next_pos) return False # 使用栈实现DFS dfs_with_stack(maze, start, end)
def dfs_with_path_selection(maze, start, end, path=[]): if start == end: print("Path found:", path) return True if start[0] < 0 or start[0] >= len(maze) or start[1] < 0 or start[1] >= len(maze[0]) or maze[start[0]][start[1]] != 0: return False maze[start[0]][start[1]] = 2 # Mark the cell as visited path.append(start) if dfs_with_path_selection(maze, (start[0]-1, start[1]), end, path) or \ dfs_with_path_selection(maze, (start[0]+1, start[1]), end, path) or \ dfs_with_path_selection(maze, (start[0], start[1]-1), end, path) or \ dfs_with_path_selection(maze, (start[0], start[1]+1), end, path): return True path.pop() # Backtrack maze[start[0]][start[1]] = 0 # Unmark the cell return False # 使用路径选择优化的DFS dfs_with_path_selection(maze, start, end)进阶技巧
def dfs_with_memoization(maze, start, end, memo=None): if memo is None: memo = {} if start == end: print("Path found:", memo[start]) return True if start in memo: return False if start[0] < 0 or start[0] >= len(maze) or start[1] < 0 or start[1] >= len(maze[0]) or maze[start[0]][start[1]] != 0: return False maze[start[0]][start[1]] = 2 # Mark the cell as visited memo[start] = start # Store current state in memo if dfs_with_memoization(maze, (start[0]-1, start[1]), end, memo) or \ dfs_with_memoization(maze, (start[0]+1, start[1]), end, memo) or \ dfs_with_memoization(maze, (start[0], start[1]-1), end, memo) or \ dfs_with_memoization(maze, (start[0], start[1]+1), end, memo): return True return False # 使用记忆化DFS dfs_with_memoization(maze, start, end)
深度优先搜索可以与许多其他算法结合使用,例如:
def dfs_with_backtracking(maze, start, end, path=[]): if start == end: print("Path found:", path) return True if start[0] < 0 or start[0] >= len(maze) or start[1] < 0 or start[1] >= len(maze[0]) or maze[start[0]][start[1]] != 0: return False maze[start[0]][start[1]] = 2 # Mark the cell as visited path.append(start) if dfs_with_backtracking(maze, (start[0]-1, start[1]), end, path) or \ dfs_with_backtracking(maze, (start[0]+1, start[1]), end, path) or \ dfs_with_backtracking(maze, (start[0], start[1]-1), end, path) or \ dfs_with_backtracking(maze, (start[0], start[1]+1), end, path): return True path.pop() # Backtrack maze[start[0]][start[1]] = 0 # Unmark the cell return False # 使用回溯法优化的DFS dfs_with_backtracking(maze, start, end)
def dfs_with_greedy(maze, start, end, path=[]): if start == end: print("Path found:", path) return True if start[0] < 0 or start[0] >= len(maze) or start[1] < 0 or start[1] >= len(maze[0]) or maze[start[0]][start[1]] != 0: return False maze[start[0]][start[1]] = 2 # Mark the cell as visited path.append(start) # Greedy choice: prioritize left, then right, then down, then up if dfs_with_greedy(maze, (start[0], start[1]-1), end, path) or \ dfs_with_greedy(maze, (start[0], start[1]+1), end, path) or \ dfs_with_greedy(maze, (start[0]+1, start[1]), end, path) or \ dfs_with_greedy(maze, (start[0]-1, start[1]), end, path): return True path.pop() # Backtrack maze[start[0]][start[1]] = 0 # Unmark the cell return False # 使用贪心策略优化的DFS dfs_with_greedy(maze, start, end)
def dfs_with_dp(maze, start, end, dp=None): if dp is None: dp = {} if start == end: print("Path found:", dp[start]) return True if start in dp: return False if start[0] < 0 or start[0] >= len(maze) or start[1] < 0 or start[1] >= len(maze[0]) or maze[start[0]][start[1]] != 0: return False maze[start[0]][start[1]] = 2 # Mark the cell as visited dp[start] = [start] if dfs_with_dp(maze, (start[0]-1, start[1]), end, dp) or \ dfs_with_dp(maze, (start[0]+1, start[1]), end, dp) or \ dfs_with_dp(maze, (start[0], start[1]-1), end, dp) or \ dfs_with_dp(maze, (start[0], start[1]+1), end, dp): return True dp[start].pop() # Backtrack maze[start[0]][start[1]] = 0 # Unmark the cell return False # 使用动态规划优化的DFS dfs_with_dp(maze, start, end)总结与展望