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

相关文章
|
6月前
|
Java 数据挖掘 数据处理
(Pandas)Python做数据处理必选框架之一!(一):介绍Pandas中的两个数据结构;刨析Series:如何访问数据;数据去重、取众数、总和、标准差、方差、平均值等;判断缺失值、获取索引...
Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。 Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据(类似于Excel表格)。 Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够轻松地从各种数据源中导入数据,并对数据进行高效的操作和分析。 Pandas 主要引入了两种新的数据结构:Series 和 DataFrame。
639 0
|
12月前
|
前端开发 Java
java实现队列数据结构代码详解
本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
531 1
|
9月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
532 1
|
存储 开发者 索引
Python 中常见的数据结构
这些数据结构各有特点和适用场景,在不同的编程任务中发挥着重要作用。开发者需要根据具体需求选择合适的数据结构,以提高程序的效率和性能
570 156
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
530 153
|
存储 开发者 Python
Python 中的数据结构与其他编程语言数据结构的区别
不同编程语言都有其设计理念和应用场景,开发者需要根据具体需求和语言特点来选择合适的数据结构
628 151
|
存储 索引 Python
Python编程数据结构的深入理解
深入理解 Python 中的数据结构是提高编程能力的重要途径。通过合理选择和使用数据结构,可以提高程序的效率和质量
557 156
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
848 77
|
10月前
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。

热门文章

最新文章

推荐镜像

更多