06.队列、python标准库中的双端队列、迷宫问题
class QueueUnderflow(ValueError):
"""队列为空"""
pass class SQueue:
def __init__(self, init_len=5):
self._len = init_len # 存储区长度
self._elems = [0] * init_len # 元素存储
self._head = 0 # 表头元素下标
self._num = 0 # 元素个数 def is_empty(self):
return self._num == 0 def peek(self):
"""查看队头元素"""
if self._num == 0:
raise QueueUnderflow
return self._elems[self._head] def dequeue(self):
"""出队"""
if self._num == 0:
raise QueueUnderflow
e = self._elems[self._head]
self._head = (self._head + 1) % self._len
self._num -= 1
return e def enqueue(self, e):
"""入队"""
if self._head == self._len - 1:
self._extend()
self._elems[(self._head + self._num) % self._len] = e
self._num += 1 def _extend(self):
"""扩容操作"""
old_len = self._len
self._len *= 2
new_elems = [0] * self._len
for i in range(old_len):
new_elems[i] = self._elems[(self._head + i) % old_len]
self._elems, self._head = new_elems, 0 def print(self):
"""打印从队头开始"""
end = self._head + self._num
print("list:", self._elems[self._head:end])
python的deque类:
import collections
# deque双端队列,支持元素的两端插入和删除,采用一种双链表技术实现
d = collections.deque()
d.append(1)
d.append(2)
d.appendleft(0)
print(d) # deque([0, 1, 2])
迷宫的递归求解:
def make(maze, pos):
"""标记maze为已走过"""
maze[pos[0]][pos[1]] = 2 def passable(maze, pos):
"""检查maze位置是否可行"""
return maze[pos[0]][pos[1]] == 0 def find_path(maze, pos, end):
dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)] # 东,南,西,北
make(maze, pos)
if pos == end:
print(pos, end=' ')
return True
for i in range(4):
nextp = [pos[0] + dirs[i][0], pos[1] + dirs[i][1]]
if passable(maze, nextp):
if find_path(maze, nextp, end):
print(pos, end=' ')
return True
return False def mazes():
"""初始化迷宫"""
map = []
for i in range(8):
map.append([])
for j in range(7):
if i == 0 or i == 7 or j == 0 or j == 6:
map[i].append(1)
else:
map[i].append(0)
return map def showMap(map):
"""打印迷宫"""
row, col = len(map), len(map[0])
for i in range(row):
for j in range(col):
print(map[i][j], end='\t')
print()
print() if __name__ == '__main__':
mmap1 = mazes()
showMap(mmap1)
print(find_path(mmap1, [1, 1], [6, 5]))
showMap(mmap1)
"""
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1 [6, 5] [5, 5] [4, 5] [3, 5] [2, 5] [1, 5] [1, 4] [1, 3] [1, 2] [1, 1] True
1 1 1 1 1 1 1
1 2 2 2 2 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 1 1 1 1 1 1
"""
基于栈的回溯解决迷宫问题:
def maze_solver(maze, start, end):
"""基于栈的回溯解决迷宫问题
算法框架:
入口start相关信息(位置和尚未探索方向)入栈;
while 栈不空:
弹出栈顶元素作为当前位置继续搜索
while 当前位置存在未走过的方向:
求出下一探测位置nextp
if nextp 是出口:
输出路径并结束
if nextp 未走过:
将当前位置和nextp顺序入栈并退出内层循环 """
dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)] # 东,南,西,北
if start == end:
print(start)
return
st = SStack()
make(maze, start) # 标记走过
# 4个方向分别编码为0,1,2,3,表示dirs的下标
st.push((start, 0)) # 入口和方向0入栈
while not st.is_empty():
pos, nxt = st.pop()
for i in range(nxt, 4):
nextp = [pos[0] + dirs[i][0], pos[1] + dirs[i][1]] # 算出下一位置
if nextp == end: # 到达出口
print(nextp, end=' ') # 终点位置
print(pos, end=' ') # 当前位置
st.print() # 经过的位置
return
if passable(maze, nextp): # 位置可行
st.push((pos, i + 1)) # 当前位置,与下一方向入栈,因为现在走的是i,如果回退就应走i+1了
make(maze, nextp)
st.push((nextp, 0)) # 新位置入栈,方向都是从0开始
break # 退出内层循环,下层讲以新栈顶为当前位置继续
print("no path found.") if __name__ == '__main__':
mmap1 = mazes()
showMap(mmap1)
print(maze_solver(mmap1, [1, 1], [6, 5])) """
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1 [6, 5] [5, 5] [([4, 5], 2), ([3, 5], 2), ([2, 5], 2), ([1, 5], 2), ([1, 4], 1), ([1, 3], 1), ([1, 2], 1), ([1, 1], 1)]
None
1 1 1 1 1 1 1
1 2 2 2 2 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 2 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
"""
基于队列的迷宫求解算法:
def maze_solver_queue(maze, start, end):
"""基于队列的迷宫求解算法:
基本框架:
将start标记为已到达
start入队
while 队列里还有未充分探查的位置:
取出一个位置pos
检查pos的相邻位置
遇到end结束
未探查的都mark并入队
队列空,探索失败
"""
dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)] # 东,南,西,北
if start == end:
print(start)
return
qu = SQueue()
make(maze, start)
qu.enqueue(start)
while not qu.is_empty():
pos = qu.dequeue()
for i in range(4):
nextp = [pos[0] + dirs[i][0], pos[1] + dirs[i][1]] # 算出下一位置
if passable(maze, nextp):
if nextp == end:
print("path find")
return
make(maze, nextp)
qu.enqueue(nextp)
print("No path.") if __name__ == '__main__':
mmap1 = mazes()
showMap(mmap1)
print(maze_solver_queue(mmap1, [1, 1], [6, 5]))
showMap(mmap1) """
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1 path find
None
1 1 1 1 1 1 1
1 2 2 2 2 2 1
1 2 2 2 2 2 1
1 2 2 2 2 2 1
1 2 2 2 2 2 1
1 2 2 2 2 2 1
1 2 2 2 2 0 1
1 1 1 1 1 1 1
"""
从打印结果看,基于栈的搜索如果顺利,可能只探查不多的位置就找到出口,是一条路径;
基于队列的搜索是一种步步为营的搜索,只有在检查完所有与入口同样距离位置之后才更多前进一步
根据搜索过程的特点:把基于栈的搜索称为深度优先搜索,
基于队列的搜索称为宽度优先搜索
06.队列、python标准库中的双端队列、迷宫问题的更多相关文章
- STL标准库-容器-deque 双端队列
头文件: #include<deque> 常用操作: https://www.cnblogs.com/LearningTheLoad/p/7450948.html
- (转)python标准库中socket模块详解
python标准库中socket模块详解 socket模块简介 原文:http://www.lybbn.cn/data/datas.php?yw=71 网络上的两个程序通过一个双向的通信连接实现数据的 ...
- Python 标准库中的装饰器
题目描述 1.简单举例 Python 标准库中的装饰器 2.说说你用过的 Python 标准库中的装饰器 1. 首先,我们比较熟悉,也是比较常用的 Python 标准库提供的装饰器有:property ...
- 8、泛型程序设计与c++标准模板库2.3双端队列容器
双端队列容器是一种放松了访问权限的队列.除了从队列的首部和尾部访问元素外,标准的双端队列也支持通过使用下标操作符"[]"进行直接访问. 它提供了直接访问和顺序访问方法.其头文件为& ...
- python中使用双端队列解决回文问题
双端队列:英文名字:deque (全名double-ended queue)是一种具有队列和栈性质的抽象数据类型. 双端队列中的元素可以从两端弹出,插入和删除操作限定在队列的两边进行. 双端队列可以在 ...
- STL队列 之FIFO队列(queue)、优先队列(priority_queue)、双端队列(deque)
1.FIFO队列 std::queue就是普通意思上的FIFO队列在STL中的模版. 1.1主要的方法有: (1)T front():访问队列的对头元素,并不删除对头元素 (2)T back(): ...
- C++实现python标准库中的Counter
看python standard library by exmple里面提到一个Counter容器,它像muliset一样,能够维持一个集合,并在常量时间插入元素.查询某个元素的个数,而且还提供了一个 ...
- Python标准库中的生成器函数
一.用于过滤的生成器函数 - 从输入的可迭代对象中产出元素的子集,而不修改元素本身 import itertools l1 = [1,2,3,4,5] l2 = [True,False,True,Fa ...
- python标准库中socket模块详解
包含原理就是tcp的三次握手 http://www.lybbn.cn/data/datas.php?yw=71 这篇讲到了socket和django的联系 https://www.cnblogs.co ...
随机推荐
- Linux shell - 重命名文件和文件夹(mv)
linux下重命名文件或文件夹的命令mv既可以重命名,又可以移动文件或文件夹. 例子:将目录A重命名为B mv A B 例子:将/a目录移动到/b下,并重命名为c mv /a /b/c
- linux中的udev(unix devices)
最开始的时候,linux预先定义了很多种设备文件,(不管这种设备是否存在), 在/dev/下 但是即使这些设备文件不存在, 这样/dev下的文件就会很多, 而且像upan在插拔顺序不同, 所对应的映射 ...
- (三)Maven之仓库
目录 引言:坐标和依赖是一个构件在Maven世界中逻辑表示方式,而构件的物理表示方式就是文件而已,仓库就是统一管理这些文件的地方. 目录 仓库类别 本地仓库 远程仓库: 中仓仓库(自带的默认远程仓库) ...
- SpringBoot系列:三、SpringBoot中使用Filter
在springboot中要使用Filter首先要实现Filter接口,添加@WebFilter注解 然后重写三个方法,下图示例是在Filter中过滤上一届中拿配置的接口,如果是这个接口会自动跳转到/P ...
- nginx坑记录
问题1: 配置解析过程使用ngx_cycle->pool申请内存保存配置,结果造成野指针. 背景:需求开发过程,有一些结构需要在配置解析阶段保存,然后可以动态修改.看原来的代码配置解析都是使用c ...
- c# WPF——完成一个简单的百度贴吧爬虫客户端
话不多说先上图 爬取10页大概500个帖子大概10s,500页2w多个帖子大概2min,由此可见性能并不是特别好,但是也没有很差. 好了话不多说,我们来一步一步实现这么个简易的客户端. 1.创建项目 ...
- 应用安全 - 代码审计 - JavaScript
JavaScript Prototype污染
- 解锁 HTTPS原理
From今日头条:https://www.toutiao.com/a6534826865792647693/?tt_from=weixin&utm_campaign=client_share& ...
- C# 保留N位小数
1.只要求保留N位不四舍五入 float f = 0.55555f; int i =(int)(f * 100); f = (float)(i*1.0) ...
- 2019寒假作业一:PTA7-1 打印沙漏
- 打印沙漏 ( 分) 本题要求你写个程序把给定的符号打印成沙漏的形状.例如给定17个“*”,要求按下列格式打印 ***** *** * *** ***** 所谓“沙漏形状”,是指每行输出奇数个符号: ...