Python数据结构学习笔记——队列和双端队列

简介: Python数据结构学习笔记——队列和双端队列

一、队列的定义


队列和栈一样,也是元素的有序集合,其元素的顺序取决于添加顺序或移除顺序,它也有两端,称作头部和尾部,栈中元素的添加操作和移除操作与栈不一样,添加操作发生在队列的尾部,移除操作发生在队列的头部。

1667140042050.jpg

队列中最先添加的元素将最先被移除,队列的排序原则被称作FIFO,即先进先出,最先添加的元素在队列头部,它最先最移出队列。

这种排列方式可以比喻成日常生活中的排队,很多人排成一队,所有的人从队的一端入队,从另一端出队,其中不能插队,后到的人若想进入队列,只能从队尾进入队列。

1667140066401.jpg

队列的相关应用例子:


在操作系统使用一些队列来控制计算机进程。

调度机制往往基于一个队列算法,其目标是尽可能快地执行程序,同时服务尽可能多的用户。在打字时,我们有时会发现字符出现的速度比击键速度慢。这是由于计算机正在做其他的工作。击键操作被放入一个类似于队列的缓冲区,以便对应的字符按正确的顺序显示。


二、队列 实现步骤分析


与栈一样,通过Python中的类与对象,在类中定义几个方法,使用列表来实现队列的相关操作,这里是将列表的末尾作为队列的头部,队列的尾部是列表下标为0处的位置,队列的操作有:

1、创建一个空队列,通过构造方法创建一个空列表;

class Queue:
    def __init__(self):
        self.items = []  # 创建一个空队列,不需要参数,且会返回一个空队列


2、向队列(尾部)中添加元素,通过列表中的insert()实现添加新元素至队列中,由于是向队列尾部添加元素,添加列表中的第一个元素,即下标为0的元素;

def add(self, item):
        self.items.insert(0, item)  # 在队列的尾部添加元素,它需要一个元素作为参数


3、删除队列头部元素,通过列表中的pop()实现删除队列头部元素,由于未指定参数,所以该方法删除列表中的末尾元素,即删除的是队列头部元素;


 

def delete(self):
        return self.items.pop()  # 删除队列头部的元素,不需要参数,它会返回一个元素,并修改队列的内容


4、返回队列的头部元素,通过len()取得队列(列表)的长度,由于列表的下标是从0开始,所以要减1,即可索引返回第一位元素;

def display(self):
        return self.items[len(self.items) - 1]  # 返回队列的头部元素


5、检查队列是否为空,通过比较运算符“==”比较队列是否为空,若为空,则返回布尔值False,若不为空,则返回True;

def isEmpty(self):
        return self.items == []  # 检查队列是否为空,不需要参数,且返回一个布尔值来表示


6、返回队列中元素数目,通过len()取所有元素的值,即返回队列中元素的数目。

def size(self):
        return len(self.items)  # 返回队列中元素的数目,不需要参数,却返回一个整数来表示


三、队列的Python实现代码


完整代码如下:

# 通过列表实现队列的操作
class Queue:
    def __init__(self):
        self.items = []  # 创建一个空队列,不需要参数,且会返回一个空队列
    def add(self, item):
        self.items.insert(0, item)  # 在队列的尾部添加元素,它需要一个元素作为参数
    def delete(self):
        return self.items.pop()  # 删除队列头部的元素,不需要参数,它会返回一个元素,并修改队列的内容
    def display(self):
        return self.items[len(self.items) - 1]  # 返回队列的头部元素
    def isEmpty(self):
        return self.items == []  # 检查队列是否为空,不需要参数,且返回一个布尔值来表示
    def size(self):
        return len(self.items)  # 返回队列中元素的数目,不需要参数,却返回一个整数来表示
# 测试
q = Queue()# q是一个新创建的空队列,创建一个对象,即对象名称=类名称()
print(q.isEmpty())  # 查询队列是否为空
print(q.size())  # 返回队列中元素的数目
q.add(False)  # 在队列的尾部添加一个元素
print(q.display())# 返回队列的头部元素
q.add("qwet")
q.add(0)
print(q.display())
print(q.size())
q.delete()  # 删除队列头部的元素
print(q.display())
print(q.size())
print(q.isEmpty())


运行结果如下:

1667140148338.jpg


四、队列的应用


六人传土豆游戏

六个人传土豆游戏可模拟为队列的循环,通过队列来模拟一个环,即队列头部的出队移至尾部,然后入队进入队列的尾部从而一直循环传下去。在出队和入队N次之后,此时位于队列头部的人出局,新一轮的游戏开始,如此反复像一个圆环一样依次循环下去,直到队列中只剩下一个名字,即最后队伍的元素数目为1。

1667140161506.jpg

定义一个Pass()函数,传递土豆的常量为7,首先通过一个for循环遍历参加传递土豆游戏的所有人使其都添加到队列中,通过add(name_people)方法实现程序实现,name_people参数可传入一个列表,然后通过while循环条件为队列中的元素是否大于1,若大于1则while循环一直执行其内部代码块下去,在while循环内根据所输入的传递土豆的常量通过for循环中的range()函数确定相应的循环次数,然后依次将所删除的头部元素再添加到队列的尾部,若循环次数(传递土豆的常量)达到后,此时删除队列头部的元素,该人出局;若直到队伍的元素数目等于1时,结束while循环返回队列中的只剩下的那个元素,完整代码及解析如下:

# 通过列表实现队列的操作
class Queue:
    def __init__(self):
        self.items = []  # 创建一个空队列,不需要参数,且会返回一个空队列
    def add(self, item):
        self.items.insert(0, item)  # 在队列的尾部添加元素,它需要一个元素作为参数
    def delete(self):
        return self.items.pop()  # 删除队列头部的元素,不需要参数,它会返回一个元素,并修改队列的内容
    def display(self):
        return self.items[len(self.items) - 1]  # 返回队列的头部元素
    def isEmpty(self):
        return self.items == []  # 检查队列是否为空,不需要参数,且返回一个布尔值来表示
    def size(self):
        return len(self.items)  # 返回队列中元素的数目,不需要参数,却返回一个整数来表示
# 定义一个有参函数,参数为参加游戏的人peoples和传土豆的计数常量num
def Pass(peoples, num):
    q = Queue()# q是一个新创建的队列,创建一个对象,即对象名称=类名称()
    for name_people in peoples:  # 依次遍历参加游戏的人peoples使其添加到队列中
        q.add(name_people)
    while q.size() > 1:  # 若队列中的元素数目大于1则while循环一直执行下去
        for i in range(num):  # 根据所给的计数常量依次进行相应的循环次数
            q.add(q.delete())  # 将所删除的头部元素添加到队列的尾部
        q.delete()  # 计数常量到达后,删除队列头部的元素,即该人出局
    return q.delete()  # 返回队列中只剩一个元素
# 测试
print(Pass(["first", "second", "third", "four", "five", "six", "seven"], 7))


运行结果如下:

1667140192014.jpg

我们可以对六人传土豆游戏进行进一步的修改,比如允许随机计数,从而使每一轮的结果都不可预测,从而使游戏更加公平,由于是随机计数,可以使用random模块来生成随机整数,选定一个范围使计算机自动生成。

改进后的六人传土豆游戏程序代码及解析如下:

import random  # 导入random模块
# 通过列表实现队列的操作
class Queue:
    def __init__(self):
        self.items = []  # 创建一个空队列,不需要参数,且会返回一个空队列
    def add(self, item):
        self.items.insert(0, item)  # 在队列的尾部添加元素,它需要一个元素作为参数
    def delete(self):
        return self.items.pop()  # 删除队列头部的元素,不需要参数,它会返回一个元素,并修改队列的内容
    def display(self):
        return self.items[len(self.items) - 1]  # 返回队列的头部元素
    def isEmpty(self):
        return self.items == []  # 检查队列是否为空,不需要参数,且返回一个布尔值来表示
    def size(self):
        return len(self.items)  # 返回队列中元素的数目,不需要参数,却返回一个整数来表示
# 定义一个有参函数,参数为参加游戏的人peoples和传土豆的计数常量num
def Pass(peoples, num):
    q = Queue()
    for name_people in peoples:  # 依次遍历参加游戏的人peoples使其添加到队列中
        q.add(name_people)
    while q.size() > 1:  # 若队列中的元素数目大于1则while循环一直执行下去
        for i in range(num):  # 根据所输入的计数常量依次进行相应的循环次数
            q.add(q.delete())  # 将所删除的头部元素添加到队列的尾部
        q.delete()  # 计数常量达到后,删除队列头部的元素,即该人出局
    return q.delete()  # 返回队列中只剩一个元素
# 测试
num = random.randint(1, 100)  # 产生1到100之间的一个整数作为计数常量值,每次产生的整数不一定相同从而无法预测到结果
print(f"本次计数常量值为:{num}")
print(Pass(["first", "second", "third", "four", "five", "six", "seven"], num))


运行结果如下,每次产生的计数常量值不同导致结果不同:

第一次运行:

1667140219060.jpg

第二次运行:

1667140230896.jpg


五、双端队列的定义


双端队列与队列类似,它有前、后两端,但无论是添加元素或删除元素都可以在两端实现,它的排序原则可以为栈的后进先出,也可以为队列的先进先出,这取决于使用者,可以说双端队列是栈和队列的结合。

1667140242411.jpg


六、双端队列 实现步骤分析


通过Python中的类与对象,在类中定义几个方法,使用列表来实现双端队列的相关操作,这里是将列表的末尾作为双端队列的前端,双端队列的后端是列表下标索引为0的位置,双端队列的操作有:

1、创建一个空双端队列,通过构造方法创建一个空列表;

class Deque:
    def __init__(self):
        self.items = []  # 创建一个空双端队列,不需要参数,且会返回一个空双端队列


2、向双端队列两端添加元素,分为向双端队列的前端或后端添加元素,前端通过append()方法向列表末尾添加元素,即向双端队列的前端添加;后端通过insert()方法在列表下标为0处列表的第一位元素,即双端队列的后端添加;

def addFront(self, item):
        self.items.append(item)  # 在双端队列的前端添加元素,它需要一个元素作为参数
    def addRear(self, item):
        self.items.insert(0, item)  # 在双端队列的后端添加元素,它需要一个元素作为参数


3、删除双端队列两端元素,分为删除双端队列的前端元素和删除双端队列的后端元素,都通过使用pop()方法,前端不需要指定参数,使其删除列表的末尾元素,即双端队列的前端元素;后端指定参数为0,使其删除列表中下标为0的元素,即列表的第一位元素,从而删除双端的后端元素;

def deleteFront(self):
        return self.items.pop()  # 删除双端队列前端的元素,不需要参数,它会返回一个元素,并修改双端队列的内容
    def deleteRear(self):
        return self.items.pop(0)  # 删除双端队列后端的元素,不需要参数,它会返回一个元素,并修改双端队列的内容


4、返回双端队列的两端元素,通过len()先取得列表的长度,由于下标是从0开始,所以要减1,从而索引得到双端队列的前端元素;通过索引列表下标为0的元素得到双端队列的后端元素;

def displayFront(self):
        return self.items[len(self.items) - 1]  # 返回双端队列的前端元素
    def displayRear(self):
        return self.items[0]  # 返回双端队列的后端元素


5、检查双端队列是否为空,通过比较运算符“==”比较队列是否为空,若为空,则返回布尔值False,若不为空,则返回True;

def isEmpty(self):
        return self.items == []  # 检查双端队列是否为空,不需要参数,且返回一个布尔值来表示


6、返回双端队列中元素数目,通过len()取所有元素的值,即返回队列中元素的数目。

 
         


七、双端队列的Python实现代码


完整代码如下:

# 通过列表实现双端队列的操作
class Deque:
    def __init__(self):
        self.items = []  # 创建一个空双端队列,不需要参数,且会返回一个空双端队列
    def addFront(self, item):
        self.items.append(item)  # 在双端队列的前端添加元素,它需要一个元素作为参数
    def addRear(self, item):
        self.items.insert(0, item)  # 在双端队列的后端添加元素,它需要一个元素作为参数
    def deleteFront(self):
        return self.items.pop()  # 删除双端队列前端的元素,不需要参数,它会返回一个元素,并修改双端队列的内容
    def deleteRear(self):
        return self.items.pop(0)  # 删除双端队列后端的元素,不需要参数,它会返回一个元素,并修改双端队列的内容
    def displayFront(self):
        return self.items[len(self.items) - 1]  # 返回双端队列的前端元素
    def displayRear(self):
        return self.items[0]  # 返回双端队列的后端元素
    def isEmpty(self):
        return self.items == []  # 检查双端队列是否为空,不需要参数,且返回一个布尔值来表示
    def size(self):
        return len(self.items)  # 返回双端队列中元素的数目,不需要参数,却返回一个整数来表示
# 测试
d = Deque()  # d是一个新创建的空双端队列,创建一个对象,即对象名称=类名称()
print(d.isEmpty())  # 检查双端队列是否为空
print(d.size())  # 返回双端队列中元素的数目
d.addFront(123456)  # 向双端队列的前端添加元素
d.addFront("45@d")
d.addRear("2021-1-14")  # 向双端队列的后端添加元素
d.addRear("Z")
print(d.size())
print(d.displayFront())  # 返回双端队列的前端元素
print(d.displayRear())  # 返回双端队列的后端元素
d.deleteFront()  # 删除双端队列的前端元素
print(d.size())
print(d.displayFront())
d.deleteRear()  # 删除双端队列的后端元素
print(d.size())
print(d.displayRear())
print(d.isEmpty())


运行结果如下:

1667140325104.jpg

测试图例:

1667140335030.jpg


八、双端队列的应用


回文检测器

回文是指正着读和反着读都一样的字符串,即成对称的字符串,例如rar、toot、12321等等,我们可以通过一个双端队列来存储字符串中的字符,通过从左往右的顺序将字符串中的字符添加到双端队列的后端,然后通过定义一个条件,只有当双端队列的前端和后端相同时,才相互抵消删除元素。一直这样删除下去,若输入的字符串字符数为偶数,则最后将没有字符;若输入的字符串字符数为奇数,则最后只剩下一个字符,从而达到检测回文的目的。

1667140348526.jpg

回文检测器的完整代码及解析如下:

# 通过列表实现双端队列的操作
class Deque:
    def __init__(self):
        self.items = []  # 创建一个空双端队列,不需要参数,且会返回一个空双端队列
    def addFront(self, item):
        self.items.append(item)  # 在双端队列的前端添加元素,它需要一个元素作为参数
    def addRear(self, item):
        self.items.insert(0, item)  # 在双端队列的后端添加元素,它需要一个元素作为参数
    def deleteFront(self):
        return self.items.pop()  # 删除双端队列前端的元素,不需要参数,它会返回一个元素,并修改双端队列的内容
    def deleteRear(self):
        return self.items.pop(0)  # 删除双端队列后端的元素,不需要参数,它会返回一个元素,并修改双端队列的内容
    def displayFront(self):
        return self.items[len(self.items) - 1]  # 返回双端队列的前端元素
    def displayRear(self):
        return self.items[0]  # 返回双端队列的后端元素
    def isEmpty(self):
        return self.items == []  # 检查双端队列是否为空,不需要参数,且返回一个布尔值来表示
    def size(self):
        return len(self.items)  # 返回双端队列中元素的数目,不需要参数,却返回一个整数来表示
# 定义一个有参函数,其参数是输入的字符串
def palindromic(string):
    d = Deque()  # d是一个新创建的空双端队列,创建一个对象,即对象名称=类名称()
    for i in string:
        d.addRear(i)  # 通过addRear()方法向双端队列的后端添加元素
    stillEqual = True
    while d.size() > 1 and stillEqual:  # 若双端队列中元素的数目大于1且变量stillEqual为True时while循环一直下去
        first = d.deleteFront()  # 通过删除双端列表前端的元素,该方法返回的元素赋值给变量first
        last = d.deleteRear()  # 通过删除双端列表后端的元素,该方法返回的元素赋值给变量last
        if first != last:
            stillEqual = False  # 若左右两端的元素不相同则对变量stillEqual赋值False
        return stillEqual  # 返回变量stillEqual的值
# 测试
print(palindromic("我为人人,人人为我"))
print(palindromic("141"))
print(palindromic("qwer"))
print(palindromic("refer"))
print(palindromic("did"))


运行结果如下:

1667140021064.jpg

相关文章
|
22天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
109 9
|
1月前
|
网络协议 Java Linux
PyAV学习笔记(一):PyAV简介、安装、基础操作、python获取RTSP(海康)的各种时间戳(rtp、dts、pts)
本文介绍了PyAV库,它是FFmpeg的Python绑定,提供了底层库的全部功能和控制。文章详细讲解了PyAV的安装过程,包括在Windows、Linux和ARM平台上的安装步骤,以及安装中可能遇到的错误和解决方法。此外,还解释了时间戳的概念,包括RTP、NTP、PTS和DTS,并提供了Python代码示例,展示如何获取RTSP流中的各种时间戳。最后,文章还提供了一些附录,包括Python通过NTP同步获取时间的方法和使用PyAV访问网络视频流的技巧。
248 4
PyAV学习笔记(一):PyAV简介、安装、基础操作、python获取RTSP(海康)的各种时间戳(rtp、dts、pts)
|
1月前
|
Python
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
使用Python的socket库实现客户端到服务器端的图片传输,包括客户端和服务器端的代码实现,以及传输结果的展示。
140 3
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
|
1月前
|
JSON 数据格式 Python
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
本文介绍了如何使用Python的socket模块实现客户端到服务器端的文件传输,包括客户端发送文件信息和内容,服务器端接收并保存文件的完整过程。
154 1
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
|
25天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
初步认识栈和队列
初步认识栈和队列
61 10
|
1月前
|
关系型数据库 MySQL 数据库
Mysql学习笔记(四):Python与Mysql交互--实现增删改查
如何使用Python与MySQL数据库进行交互,实现增删改查等基本操作的教程。
67 1
|
1月前
|
Ubuntu Linux Python
Ubuntu学习笔记(六):ubuntu切换Anaconda和系统自带Python
本文介绍了在Ubuntu系统中切换Anaconda和系统自带Python的方法。方法1涉及编辑~/.bashrc和/etc/profile文件,更新Anaconda的路径。方法2提供了详细的步骤指导,帮助用户在Anaconda和系统自带Python之间进行切换。
91 1
|
1月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
23 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
1月前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
17 0
下一篇
无影云桌面