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标准库中的双端队列、迷宫问题的更多相关文章

  1. STL标准库-容器-deque 双端队列

    头文件: #include<deque> 常用操作: https://www.cnblogs.com/LearningTheLoad/p/7450948.html

  2. (转)python标准库中socket模块详解

    python标准库中socket模块详解 socket模块简介 原文:http://www.lybbn.cn/data/datas.php?yw=71 网络上的两个程序通过一个双向的通信连接实现数据的 ...

  3. Python 标准库中的装饰器

    题目描述 1.简单举例 Python 标准库中的装饰器 2.说说你用过的 Python 标准库中的装饰器 1. 首先,我们比较熟悉,也是比较常用的 Python 标准库提供的装饰器有:property ...

  4. 8、泛型程序设计与c++标准模板库2.3双端队列容器

    双端队列容器是一种放松了访问权限的队列.除了从队列的首部和尾部访问元素外,标准的双端队列也支持通过使用下标操作符"[]"进行直接访问. 它提供了直接访问和顺序访问方法.其头文件为& ...

  5. python中使用双端队列解决回文问题

    双端队列:英文名字:deque (全名double-ended queue)是一种具有队列和栈性质的抽象数据类型. 双端队列中的元素可以从两端弹出,插入和删除操作限定在队列的两边进行. 双端队列可以在 ...

  6. STL队列 之FIFO队列(queue)、优先队列(priority_queue)、双端队列(deque)

    1.FIFO队列   std::queue就是普通意思上的FIFO队列在STL中的模版. 1.1主要的方法有: (1)T front():访问队列的对头元素,并不删除对头元素 (2)T back(): ...

  7. C++实现python标准库中的Counter

    看python standard library by exmple里面提到一个Counter容器,它像muliset一样,能够维持一个集合,并在常量时间插入元素.查询某个元素的个数,而且还提供了一个 ...

  8. Python标准库中的生成器函数

    一.用于过滤的生成器函数 - 从输入的可迭代对象中产出元素的子集,而不修改元素本身 import itertools l1 = [1,2,3,4,5] l2 = [True,False,True,Fa ...

  9. python标准库中socket模块详解

    包含原理就是tcp的三次握手 http://www.lybbn.cn/data/datas.php?yw=71 这篇讲到了socket和django的联系 https://www.cnblogs.co ...

随机推荐

  1. vue路由实例

    router.js: import Vue from 'vue' import Router from 'vue-router' import Home from '@/components/Home ...

  2. 冲刺周四The Fourth Day

    一.Fourth Day照片 二.项目分工 三.今日份燃尽图 四.项目进展 码云团队协同环境构建完毕 利用Leangoo制作任务分工及生成燃尽图 完成AES加解密部分代码 用代码实现对文件的新建.移动 ...

  3. C++返回栈上的数组(局部变量)问题探索

    char* teststr() { char s[] = "hello"; return s; } void main() { char* str = teststr(); ]; ...

  4. ora600

    4节点RAC:版本oracle11.2.0.4 22:20——23:40发生ora600 alert日志: Errors in file /u01/app/oracle/diag/rdbms/orcl ...

  5. 模拟赛DAY1 T1大美江湖

    这就是一个模拟题,注意1234分别对应左右上下横坐标和纵坐标的判断就好了 题解: 需要注意的是,向上取整ceil函数是对于一个double值返回一个double值,也就是说在ceil里面的类型一定要是 ...

  6. iOS即时通讯之CocoaAsyncSocket源码解析二

    原文 前言 本文承接上文:iOS即时通讯之CocoaAsyncSocket源码解析一 上文我们提到了GCDAsyncSocket的初始化,以及最终connect之前的准备工作,包括一些错误检查:本机地 ...

  7. AtomicBoolean 源码分析

    AtomicBoolean AtomicBoolean 能解决什么问题?什么时候使用 AtomicBoolean? 可原子更新的 boolean 值 1)原子性:在Java中,对基本数据类型变量的读取 ...

  8. C# out 和 ref 区别

    C#里面的 out 和ref参数时常会用到 记录一下: public void Start() { //outSum没必要赋值,赋值了也完全没用. //如果AddByOut函数内部直接使用out对应的 ...

  9. NanUI

    https://github.com/NetDimension/NanUI/wiki/%E4%B8%AD%E6%96%87%E8%AF%B4%E6%98%8E NanUI基于ChromiumFX项目进 ...

  10. 【ABAP系列】SAP ALV 导出报表数据 始终使用选定的格式”,一旦勾上,就再也不会弹出选择框了。

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ALV 导出报表数据 始 ...