基于c++版本的数据结构改-python栈和队列思维总结

##栈部分-(叠猫猫)

##抽象数据类型栈的定义:是一种遵循先入后出的逻辑的线性数据结构。

换种方式去理解这种数据结构如果我们在一摞盘子中取到下面的盘子,我们首先要把最上面的盘子依次拿走,才可以继续拿下面的盘子,我们把盘子替代成各种类型的元素(如整形,字符,对象等),对于栈就是类似这种衍生出来的线性数据结构。

##栈的定义(c++):是限定仅在表尾进行插入或删除操作的线性表

##图例介绍

##LIFO结构:

##动态过程

##栈的表示和实现

##栈常用操作:pop(),push(),peek()

然而,某些语言可能没有专门提供栈类,这时我们可以将该语言的“数组”或“链表”当作栈来使用,并在程序逻辑上忽略与栈无关的操作。

栈遵循先入后出的原则,我们只能在栈顶添加或删除元素。

但是,数组和链表都可以在任意位置添加和删除元素,所以栈可以看作是一种受限制的数组或链表。

##栈的顺序表示-基于数组的实现

采用具有一块连续存储的地址进行相关操作,具有代表性的便是数组,基于数组的实现栈。

我们可以将数组的尾部视作栈顶,入栈和出栈操作分别对应在数组的尾部添加或者删除元素,时间复杂度都为O(1)。

##图解

##python代码实现

考虑到入栈的元素可能会远远不断的地增加,因此我们可以使用动态数组,这样就可以不用自行处理数组的扩容问题。

在进行代码介绍之前,我们先介绍一下Python中类class基础篇(用简单的话来说,类是一个模板,而实例则是根据类创建的对象)

##Python类的定义与实例的创建

类的创建-类通过 class 关键字定义,类名通用习惯为首字母大写

class Circle(object):#创建Circle类,Circle为类名

        pass#此处可添加属性和方法

实例的创建-创建实例使用 类名+(),类似函数调用的形式创建。

circle1 = Circle()

circle = Circle()

##Python类中的实例属性与类属性

实例属性:用于区分不同的实例

类属性:是每个实例的共有属性

区别:实例属性每个实例都各自拥有,相互独立;而类属性有且只有一份,是共有的属性。

circle1.r = 1#r为实例属性

circle2.R= 2

print(circle.r)#使用 实例名,属性名,可以访问我们的属性

print(circle.R)

在定义 Circle 类时,可以为 Circle 类添加一个特殊的 __init__() 方法,当创建实例时,__init__() 方法被自动调用为创建的实例增加实例属性。

class Circle(object):  # 创建Circle类def __init__(self, r): # 初始化一个属性r(不要忘记self参数,他是类下面所有方法必须的参数)self.r = r  # 表示给我们将要创建的实例赋予属性r赋值
class Circle(object):  # 创建Circle类def __init__(self, R):  # 约定成俗这里应该使用r,它与self.r中的r同名self.r = Rcircle1 = Circle(1)  
print(circle1.r)  #我们访问的是小写r

类属性-实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。

class Circle(object):pi = 3.14  # 类属性def __init__(self, r):self.r = rcircle1 = Circle(1)
circle2 = Circle(2)
print('----未修改前-----')
print('pi=\t', Circle.pi)
print('circle1.pi=\t', circle1.pi)  #  3.14
print('circle2.pi=\t', circle2.pi)  #  3.14
print('----通过类名修改后-----')
Circle.pi = 3.14159  # 通过类名修改类属性,所有实例的类属性被改变
print('pi=\t', Circle.pi)   #  3.14159
print('circle1.pi=\t', circle1.pi)   #  3.14159
print('circle2.pi=\t', circle2.pi)   #  3.14159
print('----通过circle1实例名修改后-----')
circle1.pi=3.14111   # 实际上这里是给circle1创建了一个与类属性同名的实例属性
print('pi=\t', Circle.pi)     #  3.14159
print('circle1.pi=\t', circle1.pi)  # 实例属性的访问优先级比类属性高,所以是3.14111   
print('circle2.pi=\t', circle2.pi)  #  3.14159
print('----删除circle1实例属性pi-----')
----未修改前-----
pi=  3.14
circle1.pi=  3.14
circle2.pi=  3.14
----通过类名修改后-----
pi=  3.14159
circle1.pi=  3.14159
circle2.pi=  3.14159
----通过circle1实例名修改后-----
pi=  3.14159
circle1.pi=  3.14111
circle2.pi=  3.14159

实例属性访问优先级比类属性高

##Python类的实例方法

class Circle(object):pi = 3.14  # 类属性def __init__(self, r):self.r = r  # 实例属性def get_area(self):""" 圆的面积 """# return self.r**2 * Circle.pi # 通过实例修改pi的值对面积无影响,这个pi为类属性的值return self.r**2 * self.pi  # 通过实例修改pi的值对面积我们圆的面积就会改变circle1 = Circle(1)
print(circle1.get_area())  # 调用方法 self不需要传入参数,不要忘记方法后的括号  输出 3.14

##基于数组栈的代码实现

class ArrayStack:"""基于数组实现额栈"""def __init__(self):"""构造方法"""self._stack:list[int] = []def size(self):"""获取栈的长度"""return len(self._stack)def is_empty(self):"""判断栈是否为空"""return self._stack == []def push(self,item):"""入栈"""self._stack.append(item)def pop(self):"""出栈"""if self.is_empty():raise IndexError("栈为空")return self._stack.pop()def peek(self):"""访问栈顶元素"""if self.is_empty():raise IndexError("栈为空")return self._stack[-1]def to_list(self):"""返回列表用于打印"""return self._stack

时间效率:在基于数组的实现中,入栈和出栈操作都在预先分配好的连续内存中进行,具有很好的缓存本地性,因此效率较高。然而,如果入栈时超出数组容量,会触发扩容机制,导致该次入栈操作的时间复杂度变为O(n) 。

空间效率:在初始化列表时,系统会为列表分配“初始容量”,该容量可能超出实际需求;并且,扩容机制通常是按照特定倍率(例如 2 倍)进行扩容的,扩容后的容量也可能超出实际需求。因此,基于数组实现的栈可能造成一定的空间浪费

##栈的链式表示

使用链表实现栈时,我们可以将链表的头结点视为栈顶,尾结点视为栈底。

在进行插入元素的时候我们只需要把结点插入链表的头部,这种方法被称为“头插法”。

在进行删除操作时只需要把头结点删除即可。

##链栈示意图

##图解

##Python链栈代码实现

class ListNode(object):"""定义链表"""def __init__(self):self.val = Noneself.next = Noneclass LinkedListStack:"""基于链表实现的栈"""def __init__(self):"""构造方法"""self._peek:ListNode | None = Noneself._size: int = 0def size(self):"""获取栈的长度"""return self._sizedef is_empty(self):"""判断栈是否为空"""return self._sizedef push(self,val):"""入栈"""node = ListNode(val)node.next = self._peekself._peek = nodeself._size += 1def pop(self):"""出栈"""if self.is_empty():raise  IndexError("栈为空")return self._peek.valdef to_list(self):"""转化为列表用于打印"""arr = []node = self._peekwhile node :arr.append(node.val)node = node.nextarr.reverse()return arr

时间效率:在基于链表的实现中,链表的扩容非常灵活,不存在上述数组扩容时效率降低的问题。但是,入栈操作需要初始化节点对象并修改指针,因此效率相对较低。不过,如果入栈元素本身就是节点对象,那么可以省去初始化步骤,从而提高效率。

空间效率:由于链表节点需要额外存储指针,因此链表节点占用的空间相对较大

##栈典型的用例

浏览器中的后退与前进、软件中的撤销与反撤销。每当我们打开新的网页,浏览器就会对上一个网页执行入栈,这样我们就可以通过后退操作回到上一个网页。后退操作实际上是在执行出栈。如果要同时支持后退和前进,那么需要两个栈来配合实现。

程序内存管理。每次调用函数时,系统都会在栈顶添加一个栈帧,用于记录函数的上下文信息。在递归函数中,向下递推阶段会不断执行入栈操作,而向上回溯阶段则会不断执行出栈操作。

##队列部分-猫猫排队

是一种遵循先入先出规则的线性数据结构。

是一种模拟排队现象,新来的人不断加入到队列尾部,而位于队列头部的人不断离开。

##抽象数据类型队列的定义

队列是一种先进先出的线性表,它只允许在表的一端进行插入,而在另一端删除元素。

##图例显示

我们将队列头部称为“队首”,尾部称为“队尾”,将把元素加入队尾的操作称为“入队”,删除队首元素的操作称为“出队”。

##队列的常用操作

##图解

##基于数组的队列实现

我们在数组中进行删除首元素的时间复杂度为O(n),这就导致了出队的操作效率低下。

采用变量front指向队首元素的索引,rear = front + size ,通过一个变量size来记录队列的长度。

基于此设计,数组中所包含的元素的有效区间为[front,rear - 1]

入队操作:只需要将元素赋值给rear索引处,并将size增加1。

出队操作:只需要将front增加1,并将size减少1。

##问题:

在不断进行入队和出队的过程中,front 和 rear 都在向右移动,当它们到达数组尾部时就无法继续移动了。为了解决此问题,我们可以将数组视为首尾相接的“环形数组”。

对于环形数组,我们需要让 front 或 rear 在越过数组尾部时,直接回到数组头部继续遍历。这种周期性规律可以通过“取余操作”来实现,

##基于数组的队列代码实现

class ArrayQueue:"""基于环形数组实现的队列"""def __init__(self,size):"""构造方法"""self._nums : list[int] = [0] *size #用于存储队列元素的数组self._front : int = 0 #队首指针,指向队首元素self._size : int = 0 #队列长度def capacity(self):"""获取队列的容量"""return  len(self._nums)def size(self):"""获取队列的长度"""return self._sizedef is_empty(self):"""判断队列是否为空"""return  self._size == 0def push(self,num):"""入队操作"""if self._size == self.capacity():raise IndexError("队列已满")#计算尾指针,指向对尾的索引 + 1#通过取余操作,实现rear超过数组尾部后回到头部rear : int = (self._front + self._size) % self.capacity()#将num添加至对尾self._nums[rear] = numself._size += 1def pop(self):"""出队"""num : int = self.peek()#队首指针指向后移动一位,若超过数组尾部后回到头部rear : int = (self._front + self._size) % self.capacity()self._size -= 1return numdef peek(self):"""访问队首元素"""if self.is_empty():raise IndexError("栈为空")return self._nums[self._front]def to_list(self):"""转化成列表用于打印"""res = [0] * self.size()j : int = self._frontfor i in range(self.size()):res[i] = self._nums[(j%self.capacity())]j += 1return  res

时间效率:在基于数组的实现中,入对和出对操作都在预先分配好的连续内存中进行,具有很好的缓存本地性,因此效率较高。然而,如果入对时超出数组容量,会触发扩容机制,导致该次入对操作的时间复杂度变为O(n) 。

空间效率:在初始化列表时,系统会为列表分配“初始容量”,该容量可能超出实际需求;并且,扩容机制通常是按照特定倍率(例如 2 倍)进行扩容的,扩容后的容量也可能超出实际需求。因此,基于数组实现的栈可能造成一定的空间浪费

##基于链表的队列实现

可以将链表的“头节点”和“尾节点”分别视为“队首”和“队尾”,规定队尾仅可添加节点,队首仅可删除节点。

##图解

##基于链表的队列实现代码

class ListNode:"""定义链表"""def __init__(self):self.val = Noneself.next = Noneclass LinkedListQueue:"""基于链表实现的队列"""def __init__(self):"""构造方法"""self._front : ListNode | None = None #头结点frontself._rear: ListNode | None = None  # 尾节点 rearself._size: int = 0def size(self):"""获取队列的长度"""return self._sizedef is_empty(self):"""判断队列是否为空"""return not self._frontdef push(self, num):"""入队"""# 尾节点后添加 numnode = ListNode(num)# 如果队列为空,则令头、尾节点都指向该节点if self._front is None:self._front = nodeself._rear = node# 如果队列不为空,则将该节点添加到尾节点后else:self._rear.next = nodeself._rear = nodeself._size += 1def pop(self) -> int:"""出队"""num = self.peek()# 删除头节点self._front = self._front.nextself._size -= 1return numdef peek(self) -> int:"""访问队首元素"""if self.is_empty():raise IndexError("队列为空")return self._front.valdef to_list(self) -> list[int]:"""转化为列表用于打印"""queue = []temp = self._frontwhile temp:queue.append(temp.val)temp = temp.nextreturn queue

##队列典型应用

淘宝订单。购物者下单后,订单将加入队列中,系统随后会根据顺序处理队列中的订单。在双十一期间,短时间内会产生海量订单,高并发成为工程师们需要重点攻克的问题。

各类待办事项。任何需要实现“先来后到”功能的场景,例如打印机的任务队列、餐厅的出餐队列等,队列在这些场景中可以有效地维护处理顺序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/201793.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Postman可以卸载了!这款IDEA插件太好用了!

Postman是大家最常用的API调试工具,那么有没有一种方法可以不用手动写入接口到Postman,即可进行接口调试操作?今天给大家推荐一款IDEA插件:Apipost Helper,写完代码就可以调试接口并一键生成接口文档!而且还…

JIRA 禁用用户自动登录

概述 当用户登录 JIRA 时,他们可以通过在单击“Log In”按钮之前选中“Remember my login”复选框,让 JIRA 记住他们的登录信息。这样做之后,“Remember my login”令牌将由 JIRA 服务器存储,并且系统会在用户的浏览器中设置包含…

智能优化算法应用:基于学生心理学算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于学生心理学算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于学生心理学算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.学生心理学算法4.实验参数设定5.算法结果…

gitLab创建新项目

1.进入git2.选择创建项目3.勾选生成readme.md文件4.邀请成员

C //例10.1 从键盘输入一些字符,逐个把它们送到磁盘上去,直到用户输入一个“#”为止。

C程序设计 (第四版) 谭浩强 例10.1 例10.1 从键盘输入一些字符,逐个把它们送到磁盘上去,直到用户输入一个“#”为止。 IDE工具:VS2010 Note: 使用不同的IDE工具可能有部分差异。 代码块 方法:使用指针&…

第一篇:MongoDB的安装、启动、关闭、链接shell

目录 简介 安装 安装遇到的问题 查看brew 当前使用的源: 更换brew 源。更换成清华大学镜像源 版本查看 MongoDB 数据目录与日志目录 启动方式一: 启动MongoDB 验证MongoDB 是否正常运行 停止或重新启动 停止MongoDB 服务 重新启动MongoDB服…

身为 Go 程序员,我为啥更喜欢用 Zig?

Zig 是一种比较新的编程语言,于 2016 年首次推出。Zig 社区将其描述为“一种用于维护稳固的、可优化和可重用软件的通用编程语言”。 看似一句简单的描述,却隐藏着远大的抱负。Zig被看作是可与C语言一较高下的编程语言。此外,Zig 也是一个编…

Python自动化测试selenium操作下拉列表实现

处理下拉列表需要使用selenium中的工具类Select,常用方法如下: 示例网站:Sahi Tests 示例场景:打开Sahi Tests页面, (1)点击“Select Test”页面,鼠标点击页面中第一个下拉列表。 …

Git版本管理配置说明 - Visual Studio

一、 Git服务端配置 在源代码管理服务器新建文件夹,并配置共享访问权限Everyone(读取/写入)。 在本地访问这台服务器共享目录,确保正确打开。 在VS中打开项目,点选Git更改,点击“创建Git仓库”,创建项目初始版本。 弹出如下对话框: 因为我们只是在局域网中开发项…

LeetCode题:931下降路径最小和

目录 一、题目要求 二、解题思路 (1)状态表示 (2)状态转移方程 (3)初始化 (4)填表顺序 (5)返回值 三、代码 一、题目要求 931. 下降路径最小和 给你…

Web测试中文件上传测试

总体情况 功能实现: (1)文件类型正确、大小合适。 (2)文件类型正确,大小不合适。 (3)文件类型错误,大小合适。 (4)文件类型和大小都合适&#xff…

路由跳转添加进度条

根据npm官网的步骤: 1.先安装nprogress npm install nprogress 2.引入nprogress和样式文件 import nprogress from nprogress import nprogress/nprogress.css 3.在前置守卫添加进度条的展示 //全局前置守卫 router.beforeEach((to: any, from: any, next: an…

Pyside2 (Qt For Python)进度条功能实现

Pyside2 (Qt For Python)进度条功能实现 进度条(QProgressBar) 今天来介绍PySide2进度条(QProgressBar)的使用,如下所示: 说明 进度条也是一个常用的控件,当程序需要做一件比较耗费时间的任…

【序列化】概念及二叉树序列化、反序列化的两种方式

序列化是什么?为什么需要序列化? 前言: (1)进程想要运行,就要向操作系统申请内存空间,进程对数据的所有操作都是在内存空间中完成的。内存中有一部分数据很重要,我们希望将这些数据存…

Slurm集群管理系统

Slurm集群管理系统 Slurm(Simple Linux Utility for Resource Management,https://slurm.schedmd.com/)是一个开源的、容错的、高度可扩展的集群管理和作业调度系统,适用于大型和小型高性能计算(HPC)集群。…

【go语言开发】go项目打包成Docker镜像,包括Dockerfile命令介绍、goctl工具生成

本文主要介绍如何将go项目打包成镜像,首先介绍Dockerfile常用命令介绍,然后介绍使用工具goctl用于生成Dockerfile,还可以根据需求自定义指令内容,最后讲解如何将go-blog项目打包成镜像,以及如何运行等 文章目录 前言Do…

提高工厂能源效率的关键:工厂能耗监测平台

工业做为能源消耗的重要场所,所以节能减排对工业来讲是一个亟需解决的问题。除了对设备进行更新换代外,还需要能源管理消耗监测平台,帮助企业实现节能减排的目标。 工厂能源消费量非常庞大,能源比较难以监测与控制。传统能源的管…

【Linux】信号的保存和捕捉

文章目录 一、信号的保存——信号的三个表——block表,pending表,handler表sigset_t信号集操作函数——用户层sigprocmask和sigpending——内核层 二、信号的捕捉重谈进程地址空间(第三次)用户态和内核态sigaction可重入函数volat…

04 硬件知识入门(二极管)

1 二极管的定义 导电性能介于导体与绝缘体之间的材料称为半导体,常见的半导体材料有硅、锗和硒等。利用半导体材料可以制作各种各样的半导体元器件,如二极管、三极管、场效应管和晶闸管等都是由半导体材料制作而成的。 2 二极管的简介 1.半…

已解决error: (-215:Assertion failed) inv_scale_x > 0 in function ‘cv::resize‘

需求背景 欲使用opencv的resize函数将图像沿着纵轴放大一倍,即原来的图像大小为(384, 512), 现在需要将图像放大为(768, 512)。 源码 import cv2 import numpy as np# 生成初始图像 img np.zeros((384, 512), dtypenp.uint8) img[172:212, 32:-32] 255 H, W …