重学数据结构之队列
队列(queue)又被称为队,也是一种保存数据元素的容器。队列时一种特殊的线性表,只允许在表的前端(front)进行删除操作,只允许在表的后端(rear)进行插入操作,进行删除操作的一端叫做对头,进行插入操作的一端称为队尾。
队列按照先进先出的原则(FIFO,First In First Out)存储数据,先存入的元素会先被取出来使用。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。
2.抽象数据描述
队列的基本操作和栈是类似的,只不过操作名称有些许不一样,下面是一个基本队列的抽象数据描述:
ADT Queue: Queue(self) # 创建一个空队列 is_empty(self) # 判断队列是否为空 enqueue(self, elem) # 入队,向队列中插入一个元素 dequeue(self) # 出队,从队列中删除一个元素 peek(self) # 查看对头位置的元素
3.用 Python 实现
1 # 自定义队列
2 class MyQueue:
3 def __init__(self):
4 self.data = []
5
6 def is_empty(self):
7 return len(self.data) == 0
8
9 def enqueue(self, elem):
10 self.data.append(elem)
11
12 def dequeue(self):
13 if self.data:
14 ret, self.data = self.data[0], self.data[1:]
15 return ret
16 return None
17
18 def peek(self):
19 return self.data[0] if self.data else None
二、队列
1.顺序队列
顺序队列是队列的顺序存储结构,顺序队列实际上是运算受限的顺序表。和顺序表一样,顺序队列使用一个向量空间来存放当前队列中的元素。由于队列的队头和队尾的位置是变化的,设置两个指针front和rear分别指示队头元素和队尾元素的位置,它们的初值在初始化时都置为0。
2.循环队列
循环队列将向量空间想象为一个首尾相接的回环,在循环队列中,由于入队时队尾指针向前追赶队头指针,出队时队头指针追赶队尾指针,因而队空和队满时头尾指针均相等。
3.双端队列
双端队列是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。双端队列是限定插入和删除操作在表的两端进行的线性表。
4.优先级队列
在优先级队列中,会给每一个元素都分配一个数字用来标记其优先级,例如给其中最小的数字以最高的优先级,这样就可以在一个集合中访问优先级最高的元素并对其进行查找和删除操作了。
使用 Python 实现一个优先级队列,可以借助 Python 中的 heapq 模块来实现,heapq 是一个二叉堆的实现,其内部使用内置的 list 对象,对于列表中的每一个元素都满足 a[k] <= a[2 * k + 1] and a[k] <= a[2 * k + 2],因此其默认是一个最小堆,a[0] 是队列中最小的元素。下面是利用 heapq 模块实现的一个优先级队列代码示例:
1 # 自定义优先级队列
2 class PriorityQueue:
3 def __init__(self):
4 self.data = []
5 self.index = 0
6
7 def push(self, elem, priority):
8 """
9 入队,将元素插入到队列中
10 :param elem: 待插入元素
11 :param priority: 该元素的优先级
12 :return:
13 """
14 # priority 加上负号是因为 heapq 默认是最小堆
15 heapq.heappush(self.data, (-priority, self.index, elem))
16 self.index += 1
17
18 def pop(self):
19 """
20 出队,从队列中取出优先级最高的元素
21 :return:
22 """
23 return heapq.heappop(self.data)[-1]
24
25 def size(self):
26 """
27 获取队列中元素数量
28 :return:
29 """
30 return len(self.data)
31
32 def is_empty(self):
33 """
34 判断队列是否为空
35 :return:
36 """
37 return len(self.data) == 0
三、队列的应用
1.迷宫问题
1)问题描述
将一个迷宫映射成一个由0和1组成的二维矩阵,迷宫里的空位置用0来表示,障碍和边界用1来表示,最左上角为入口,最右下角为出口,求是否能从迷宫中走出来?
2)问题分析
首先在算法初始时,可行的位置用0标识,不可行的位置用1标识,但在搜索路径的过程中需要将已经走过的位置给标记上,这里可以用数字2来标记,在后面的搜索过程中碰到2也就不会重复搜索了。
当到达一个位置时,需要确定该位置的可行方向,而除了边界点,每个位置都有四个可行的方向需要探索,例如对于坐标点(i,j),其四个相邻位置如下图:
为了能够方便的计算相邻位置,可以用一个列表来记录:
DIR = [(0, 1), (1, 0), (0, -1), (-1, 0)]
对于任何一个位置(i,j),都可以分别加上 DIR[0]、DIR[1]、DIR[2]、DIR[3],就能得到相邻位置了。
为了使算法变得简单,这里可以先定义两个辅助用的函数,一个用于标记走过的点,一个用于判断输入的位置是否可以通行,具体代码如下:
1 def mark(maze, pos):
2 """
3 将迷宫中已经走过的位置进行标记,设置为2
4 :param maze: 迷宫
5 :param pos: 位置
6 :return:
7 """
8 maze[pos[0]][pos[1]] = 2
9
10
11 def passable(maze, pos):
12 """
13 检车迷宫中指定位置是否能走
14 :param maze: 迷宫
15 :param pos: 位置
16 :return:
17 """
18 if pos[0] < len(maze) and pos[1] < len(maze[0]):
19 return maze[pos[0]][pos[1]] == 0
20 return False
3)递归算法求解
在使用递归算法求解的过程中,对于每一个位置,都有如下的算法过程:
- 标记当前位置;
- 检查当前位置是否为出口,如果则表明找到路径,算法结束,不是则进行下一步;
- 遍历该位置的相邻位置,使用递归调用自身;
- 如果相邻位置都不可行,表明无法从迷宫中走出来,算法结束。
递归算法的核心函数代码如下:
- Nginx开启fastcgi_cache缓存加速,支持html伪静态页面
- Go-指针、传值与传引用、垃圾回收
- SEO分享:彻底禁止搜索引擎抓取/收录动态页面或指定路径的方法
- Go-defer,panic,recover
- SEO技巧:Shell脚本自动提交网站404死链到搜索引擎
- Nginx发布1.9.0版本,新增支持TCP代理和负载均衡的stream模块
- WordPress4.2升级修复补丁:解决大量404请求以及评论表情路径及尺寸异常问题
- Linux系统编译安装Redis以及主从复制配置小记
- Go-Maps
- 为WordPress开启Nginx缩略图功能,七牛从此陌路
- 为网站开启Nginx缓存加速,支持html伪静态页面
- 解决WordPress升级4.2后调用国外图片导致大量404请求的问题
- JS代码实现浏览器网页标题的动态切换,略微提高网站粘性
- Go-List
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- shutil模块,为什么说它是os模块的兄弟模块?
- HTML5+CSS3项目实战之河马牙医首页、百度首页、Mac桌面、简书首页、登录注册页面、苏宁易购首页
- 【Vue.js】Vue.js中的Vuex、Vue-Ajax和京东购物车项目实战
- ubuntu16.04安全小结-01
- 重新认识HTTP3xx重定向机制
- 【Vue.js】Vue.js中常用的UI组件库和Vue Router
- 四大查找算法
- 从Python调用堆栈获取行号等信息
- 详解supervisor进程管理
- Python时间模块常用操作总结
- rtmp规范1.0
- 实战|Python轻松实现动态网页爬虫(附详细源码)
- 排序算法 --- 桶排序
- 8086汇编语言——操作内存中的数据
- JVM内存模型不再是秘密