迷宫问题:深度优先搜索和广度优先搜索
1、深度优先搜索可以使用栈实现,栈顶元素为当前节点
2、当前节点搜索下一节点,判断节点是否走得通,如果走得通任意方向走一步,走不通一直弹出栈内元素,直到走得通
3、当前节点如果等于(x2,y2)说明搜索结束,已找到出口
4、对于每一个走过的路径都要标记为另一个数,便于下次不能搜索到
一、深度优先搜索
maze = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 1, 1, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]
dirs = [lambda x, y: (x - 1, y),
lambda x, y: (x + 1, y),
lambda x, y: (x, y - 1),
lambda x, y: (x, y + 1)]
# 深度有优先搜索
def maze_path(x1, y1, x2, y2):
'''(x1,y1)代表起点,(x2,y2)代表终点'''
global nextNode
stack = []
stack.append((x1, y1)) # 开始时候起点进栈
while len(stack) > 0: # 只要栈不空代表还可以继续搜素
curNode = stack[-1] # 栈顶的元素为当前的路径
if curNode[0] == x2 and curNode[1] == y2: # 走到终点
for p in stack:
print("找到的路径为:", p)
return True
# 向四个方向搜索,上下左右,找到下一个可以走的节点
for dir in dirs:
nextNode = dir(curNode[0], curNode[1])
# 如果有一个方向上为0则说明可以按照该方向继续走
if maze[nextNode[0]][nextNode[1]] == 0:
stack.append(nextNode)
maze[nextNode[0]][nextNode[1]] = 2 # 标志为2说明当前节点走过了,找到一个可以走的点就结束
break # 跳出for的循环,只要栈不空就进入下一次寻找方向
else:
maze[nextNode[0]][nextNode[1]] = 2 # 没找到路也要标记,并把栈中的元素弹出
stack.pop()
else:
print("没有路")
return False
二 、广度优先搜索
1、广度优先搜素使用队列实现,但是队列实现时队内只保留当前路径的最后一个节点,所以队空了说明没有路可以走了
2、每次走下一步时需要一个列表把当前节点的上一个节点存下来,最后通过回溯找到该节点所在的路径
3、回溯函数要单独来写,判断的条件只要不是起始点就一直往回找,并把节点单独存放到一个列表中
4、如此找到的节点保存到realPath中是从终点到起点的,将列表逆序之后找到的就是该条路径
5、当找到路的时候,终点也会被放到path里,所以path的最后一个元素就是终点,回溯的时候就是通过终点往回找的
6、path里边放的是所有出队的节点,但是只有一条路径是最后到了终点的路径,根据回溯找到那条路径上所有的节点
from collection import deque
# 路径回溯函数
def print_path(path):
curNode = path[-1]
realPath = []
while curNode[2] != -1: # curNode[2] == -1 代表搜索到了起始位置
realPath.append(curNode[0:2]) # curNode的前两个存放的就是真实走过的路径
curNode = path[curNode[2]]
# while循环结束将起点加入到路径中
realPath.append(curNode[0:2])
realPath.reverse() # 当前路径为终点到起点,列表反转
# print(realPath)
for p in realPath:
print(p)
def maze_path_deque(x1, y1, x2, y2):
queue = deque() # -1代表起点的前一个节点的下标
queue.append((x1, y1, -1))
path = [] # 把出队的节点存起来,下一个节点回溯找到走过的路
while len(queue) > 0:
curNode = queue.pop()
path.append(curNode)
if curNode[0] == x2 and curNode[1] == y2:
print_path(path)
return True
for dir in dirs:
nextNode = dir(curNode[0], curNode[1])
if maze[nextNode[0]][nextNode[1]] == 0:
queue.append((nextNode[0], nextNode[1], len(path) - 1)) # 后续节点进队,记录是由哪一个节点出队使它进队的
# 标记走过的路线
maze[nextNode[0]][nextNode[1]] = 2
else:
print("没有路")
return False
三、广度优先搜索(myself)
from collections import deque
maze = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 1, 1, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]
dirs = [lambda x, y: (x - 1, y),
lambda x, y: (x + 1, y),
lambda x, y: (x, y - 1),
lambda x, y: (x, y + 1)]
# 深度优先搜索实现队列,找到最短的路径
# 返回路径
def print_path(path):
curNode = path[-1]
real_path = []
# 只要没有到起点,弹出没一个节点的下标
while curNode[2] != -1:
real_path.append(curNode[0:2])
curNode = path[curNode[2]]
real_path.append(curNode[0:2]) # 如果是起点的话将起点也加进来
real_path.reverse() # 原来是终点到起点,逆序起点到终点
for item in real_path:
print(item)
def maze_path(x1, y1, x2, y2): # (x1,y1)代表起点,(x2,y2)代表终点
stack = deque()
path = []
stack.append((x1, y1, -1)) # 起点进栈
while len(stack) > 0:
curNode = stack.pop()
path.append(curNode) # 每一个出队的都要保存下来
if curNode[0] == x2 and curNode[1] == y2:
# print("找到路")
print_path(path)
return True
for dir in dirs:
nextNode = dir(curNode[0], curNode[1]) # 计算下一个节点
if maze[nextNode[0]][nextNode[1]] == 0:
stack.append((nextNode[0], nextNode[1], len(path) - 1))
maze[nextNode[0]][nextNode[1]] = 2
else:
print("没有路走")
return False
``