一、双向队列
两端都支持 进队 和 出队 操作。
双向队列的基本操作:
- 队首进队、队首出队、队尾进队、队尾出队
二、python队列的内置模块
使用方法: from collections import deque
- 创建队列: queue = deque()
- 队尾进队: append( )
- 队头出队: popleft( )
- 双向队列队首进队:qppendleft( )
- 双向队列队尾出队: pop( )
from collections import deque
q = deque([1,2,3])
# 单向队列实现
q.append(4) # 右边-队尾进队
print(q) # deque([1,2,3,4])
print(q.popleft()) # 左边-队首出队 : 只要没有left,就都是右边队尾的操作
# 用于双向队列
q.appendleft(0) # 左边-队首进队
q.pop() # 右边-队尾出队
q2 = deque([1,2,3,4,5],5) # 后边的参数是队列中数据个数,队满之后在加数据,前面的自动出队
q2.append(6)
print(q2) # deque([2,3,4,5,6])
print(q2.popleft()) # 2 出队
队列的应用:打印文件后几行
前几行只需要for循环读,读到第五行break即可。
from collections import deque
def tail(n):
with open('test.txt','r') as f:
q = deque(f,n) #创建一个容量为n的队列
return q
print(tail(5)) # 打印出文件中的后5行,为什么会存后5行:
# 读f文件,从上到下,先将前n行存入队列; 接着再往后读,因为队列已满,前面的
# 只能出队,最后只剩下最后n行
for line in tail(5): # 从队头开始出队
print(line,end='')
>>>deque(['6\n', '7\n', '8\n', '9\n', '10'], maxlen=5)
>>>6
>>>7
>>>8
>>>9
>>>10
三、栈和队列的应用---迷宫问题
1. 栈——深度优先搜索:回溯法
“一条路走到黑”
思路:从一个节点开始,任意找下一个能走的点。当找不到能走的点时,退回上一个寻找是否有其他方向的点。
使用栈存储当前路径(后进先出)
#深度优先搜索————栈————回溯法
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)
stack=[] # 建栈
stack.append((x1,y1))
maze[x1][y1] = 2 # 将起点先标记为走过的路
while len(stack) > 0: # 栈不为空,继续循环
curNode = stack[-1] # 现在的位置
if (curNode[0],curNode[1]) == (x2,y2): # 如果找到终点:
print('找到路了,路线如下:')
for p in stack:
print(p)
return True
for dir in dirs:
nextNode = dir(curNode[0],curNode[1])
if maze[nextNode[0]][nextNode[1]] == 0: # 如果下一个位置为0 ,可以进栈
stack.append(nextNode)
maze[nextNode[0]][nextNode[1]] = 2 # 走过的位置 设为2
break # 某个方向上可以走,就进栈,进栈后就结束for,不在看其他方向
else: # 如果每个方向上都不为0:即没有路可走----退一步(出栈)
stack.pop()
else: # 如果len(stack) == 0,空栈,说明没有路
print('没有路')
return False
maze_path(1,1,8,8)
1. 队列——广度优先搜索
同时考虑多条路!可以找到最短的那条
思路:从一个节点开始,寻找所有接下来能继续走的点,继续不断寻找,直到找到出口。
使用队列存储当前正在考虑的节点(已经考虑过的节点不在队列里存储)
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]
]
from collections import deque
# 决定查找的四个方向的先后
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_r(path):
curNode=path[-1]
real_path = [] # path不是真正的路径,是所有被出队的元素及其来源
while curNode[2] != -1: # 表示没到开头---继续往前找
real_path.append(curNode[0:2])
curNode = path[curNode[2]]
real_path.append(curNode[0:2]) # 等到curNode[2]==1 时,说明到起点位置,也需要添加到真实路径
real_path.reverse()
for node in real_path:
print(node)
def maze_path_queue(x1,y1,x2,y2): # 起点(x1,y1) 终点(x2,y2)
queue=deque() # 创建一个队列:存储正在考虑的节点
queue.append((x1,y1,-1)) # 起点(x1,y1),第三个参数代表来自哪个位置
path=[] # 每个元素里都是三维的
while len(queue) > 0: # 队列不为空,可以继续找
curNode = queue.pop() # 从该节点后面开始找
path.append(curNode) # 记录所有出队的数据,他代表下一个节点的来源
if curNode[0] == x2 and curNode[1] == y2: # 如果找到终点
print_r(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)) # 第三个参数代标该节点的来源,它来源于已经出队的数据的位置——path
maze[nextNode[0]][nextNode[1]] = 2
else:
print('没路了')
return False
maze_path_queue(1,1,8,8)