数据结构与算法--栈、队列篇
一、计算机领域的地位
在计算机科学的广袤领域中,数据结构犹如一座精巧的大厦,为信息的存储和处理提供了坚实的框架。而在众多的数据结构中,栈和队列宛如两颗璀璨的明珠,各自闪耀着独特的光芒。
栈和队列虽然看似简单,却蕴含着深刻的逻辑和强大的功能。它们是解决众多复杂问题的基石,从程序的执行流程控制到各种算法的优化,从操作系统的任务调度到网络通信中的数据传输,栈和队列都发挥着不可或缺的作用。
深入理解栈和队列,不仅能够提升我们对数据组织和操作的认知,更能为我们在编程和算法设计中打开新的思路,使我们能够更加高效、优雅地解决实际问题。在接下来的篇章中,让我们一同走进栈和队列的精彩世界,探索它们的奥秘与魅力。
二、栈(Stack)的详解
栈是一种特殊的线性表,其操作遵循“后进先出(Last In First Out,LIFO)”的原则。
一、栈的定义
栈只允许在一端进行插入(入栈)和删除(出栈)操作,这一端被称为栈顶,而另一端则被称为栈底。
二、栈的基本操作
-
入栈(Push):将元素添加到栈顶。
- 例如,一个初始为空的栈,依次入栈元素 10、20、30 ,此时栈顶元素为 30 。
-
出栈(Pop):删除栈顶元素。
- 对于上述栈,执行出栈操作,先弹出的是 30 。
-
读取栈顶元素(Peek):获取栈顶元素的值,但不删除它。
-
判空(IsEmpty):判断栈是否为空。
三、栈的实现方式
-
顺序栈:使用数组来实现。
- 优点:操作简单,随机访问速度快。
- 缺点:需要预先分配固定大小的空间,可能造成空间浪费或溢出。
下面是用python实现的顺序栈结构:
# 顺序栈实现
class SequentialStack:def __init__(self, size=10):"""初始化顺序栈参数:size (int): 栈的初始大小"""self.stack = [None] * size # 存储栈元素的列表self.top = -1 # 栈顶指针def is_empty(self):"""判断栈是否为空返回:bool: 如果栈为空返回 True,否则返回 False"""return self.top == -1def is_full(self):"""判断栈是否已满返回:bool: 如果栈已满返回 True,否则返回 False"""return self.top == len(self.stack) - 1def push(self, element):"""向栈中压入元素参数:element: 要压入栈的元素异常:Exception: 如果栈已满,抛出"Stack Overflow"异常"""if self.is_full():raise Exception("Stack Overflow")self.top += 1self.stack[self.top] = elementdef pop(self):"""从栈中弹出元素返回:弹出的元素异常:Exception: 如果栈为空,抛出"Stack Underflow"异常"""if self.is_empty():raise Exception("Stack Underflow")element = self.stack[self.top]self.stack[self.top] = Noneself.top -= 1return elementdef peek(self):"""查看栈顶元素但不弹出返回:栈顶元素异常:Exception: 如果栈为空,抛出"Stack is empty"异常"""if self.is_empty():raise Exception("Stack is empty")return self.stack[self.top]
2. 链式栈:使用链表来实现。
- 优点:灵活,不受固定空间限制。
- 缺点:访问节点需要遍历,效率相对较低。
下面是用python实现的链式栈结构:
# 链式栈节点
class Node:def __init__(self, data=None):"""初始化链式栈节点参数:data: 节点存储的数据,默认为 None"""self.data = dataself.next = None# 链式栈实现
class LinkedStack:def __init__(self):"""初始化链式栈"""self.top = None # 栈顶节点def is_empty(self):"""判断链式栈是否为空返回:bool: 如果为空返回 True,否则返回 False"""return self.top is Nonedef push(self, element):"""向链式栈中压入元素参数:element: 要压入的元素"""new_node = Node(element) # 创建新节点new_node.next = self.top # 新节点指向当前栈顶self.top = new_node # 更新栈顶def pop(self):"""从链式栈中弹出元素返回:弹出的元素异常:Exception: 如果栈为空,抛出"Stack Underflow"异常"""if self.is_empty():raise Exception("Stack Underflow")element = self.top.data # 获取栈顶节点数据self.top = self.top.next # 更新栈顶return elementdef peek(self):"""查看链式栈栈顶元素但不弹出返回:栈顶元素异常:Exception: 如果栈为空,抛出"Stack is empty"异常"""if self.is_empty():raise Exception("Stack is empty")return self.top.data
四、栈的应用场景
-
函数调用:函数的调用和返回可以通过栈来管理。
- 当一个函数被调用时,相关的参数、局部变量等信息被压入栈中;函数返回时,这些信息从栈中弹出。
-
表达式求值:如中缀表达式转后缀表达式,然后进行计算。
-
括号匹配:检查表达式中的括号是否正确匹配。
-
回溯算法:在搜索过程中保存当前状态,以便回溯。
总之,栈虽然结构简单,但在计算机科学的众多领域中发挥着重要作用,是理解和解决许多复杂问题的基础工具。
三、队列(Queue)的详解
一、队列的定义
队列只允许在一端进行插入操作(称为队尾,Rear),在另一端进行删除操作(称为队头,Front)。
二、队列的基本操作
-
入队(Enqueue):将元素添加到队尾。
- 例如,一个初始为空的队列,依次入队元素 5、15、25 ,此时队头元素为 5 。
-
出队(Dequeue):删除队头元素。
- 对于上述队列,执行出队操作,先弹出的是 5 。
-
读取队头元素(Front):获取队头元素的值,但不删除它。
-
判空(IsEmpty):判断队列是否为空。
-
判满(IsFull):对于有固定大小的队列,判断是否已满。
三、队列的实现方式
-
顺序队列:使用数组来实现。
- 可能会出现“假溢出”的情况,即队列未满但无法再插入元素。
- 为解决此问题,可采用循环队列的方式。
以下是用python代码实现的顺序队列:
class SequentialQueue:def __init__(self, size=10):self.queue = [None] * sizeself.front = 0self.rear = 0def is_empty(self):return self.front == self.reardef is_full(self):return (self.rear + 1) % len(self.queue) == self.frontdef enqueue(self, element):if self.is_full():raise Exception("Queue Overflow")self.queue[self.rear] = elementself.rear = (self.rear + 1) % len(self.queue)def dequeue(self):if self.is_empty():raise Exception("Queue Underflow")element = self.queue[self.front]self.queue[self.front] = Noneself.front = (self.front + 1) % len(self.queue)return elementdef get_front(self):if self.is_empty():raise Exception("Queue is empty")return self.queue[self.front]
创建一个队列对象即可使用。
-
链式队列:使用链表来实现。
以下是用python实现的链式队列:
class Node:def __init__(self, data=None):self.data = dataself.next = Noneclass Queue:def __init__(self):self.front = Noneself.rear = Nonedef enqueue(self, data):new_node = Node(data)if not self.rear:self.front = new_nodeself.rear = new_nodeelse:self.rear.next = new_nodeself.rear = new_nodedef dequeue(self):if not self.front:return "Queue is empty"temp = self.frontif self.front == self.rear:self.front = Noneself.rear = Noneelse:self.front = self.front.nextreturn temp.datadef is_empty(self):return self.front is Nonedef print_queue(self):current = self.frontwhile current:print(current.data, end=" ")current = current.nextprint()# 测试队列
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
q.print_queue()
print(q.dequeue())
q.print_queue()
经测试,得出链式队列具有较强的稳定性。
四、队列的应用场景
-
任务调度:操作系统按照任务进入队列的先后顺序进行调度。
-
消息队列:在分布式系统中用于消息的传递和处理。
-
广度优先搜索:在图的遍历中使用队列来保存待访问的节点。
总之,队列以其独特的先进先出特性,在计算机科学和实际应用中发挥着重要作用,为数据的有序处理提供了有效的手段。
四、BFS(广度优先搜索)和队列的关系:
BFS 通常使用队列来实现。在 BFS 中,我们先访问起始节点,然后将其相邻节点放入队列。接着依次取出队列头部的节点,并将其未访问过的相邻节点放入队列。这个过程一直持续,直到队列为空。
例如,对于一个简单的二叉树:
class TreeNode:def __init__(self, value):self.value = valueself.left = Noneself.right = None# 构建二叉树
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)def bfs(root):queue = [root]while queue:current = queue.pop(0)print(current.value)if current.left:queue.append(current.left)if current.right:queue.append(current.right)bfs(root)
五、DFS(深度优先搜索)和栈的关系:
DFS 通常使用栈来实现。在 DFS 中,我们先访问起始节点,然后将其相邻节点压入栈。接着取出栈顶节点,并将其未访问过的相邻节点压入栈。这个过程一直持续,直到栈为空。
以下是一个使用栈实现 DFS 的示例:
def dfs(root):stack = [root]while stack:current = stack.pop()print(current.value)if current.right:stack.append(current.right)if current.left:stack.append(current.left)dfs(root)
总结:
队列是先进先出的数据结构,适合 BFS 逐层扩展搜索。栈是先进后出的数据结构,适合 DFS 深入一条路径后再回溯。通过这些数据结构的特性,能够有效地实现不同的搜索策略。
例如,在图的遍历中,如果要尽快找到距离起始节点较近的所有节点,通常使用 BFS;而如果要探索整个图的所有可能路径或者找到一条到达目标节点的最长路径,可能会使用 DFS。
“且将新火试新茶,诗酒趁年华”——《望江南·超然台作》
相关文章:
数据结构与算法--栈、队列篇
一、计算机领域的地位 在计算机科学的广袤领域中,数据结构犹如一座精巧的大厦,为信息的存储和处理提供了坚实的框架。而在众多的数据结构中,栈和队列宛如两颗璀璨的明珠,各自闪耀着独特的光芒。 栈和队列虽然看似简单&…...
【程序、游戏、人生】致敬飞逝的3年和新的开始
人,总要向前看。 感谢之前关注的朋友,感谢各位朋友的私信、感谢关心的评论。 不要停下 20年:某银行业务三方开发。 21年:移动内部业务平台开发移动物联网商城开发储备TPL。 22年-至今:手游发行技术综合北漂 经历了行…...
第三届人工智能、人机交互与机器人国际会议
国际人工智能、人机交互和机器人会议是一项年度活动,汇集了来自世界各地的研究人员、从业者和行业专业人士,分享他们在人工智能、人际交互和机器人领域的知识和专业知识。在过去的几十年里,这些领域在计算能力、数据分析和机器学习技术的进步…...

AWS生成式AI项目的全生命周期管理
随着人工智能技术的迅速发展,生成式 AI 已成为当今最具创新性和影响力的领域之一。生成式 AI 能够创建新的内容,如文本、图像、音频等,具有广泛的应用前景,如自然语言处理、计算机视觉、创意设计等。然而,构建一个成功…...
windows go grpc
windows环境安装go grpc 的工具和插件 在Windows环境下,安装Protocol Buffers(proto)和gRPC相关的工具和插件,可以通过以下几个步骤进行 1.安装protoc 在git 仓库下载tag 包 https://github.com/protocolbuffers/protobuf/rele…...

Leetcode 第 135 场双周赛题解
Leetcode 第 135 场双周赛题解 Leetcode 第 135 场双周赛题解题目1:3222. 求出硬币游戏的赢家思路代码复杂度分析 题目2:3223. 操作后字符串的最短长度思路代码复杂度分析 题目3:3224. 使差值相等的最少数组改动次数思路代码复杂度分析 题目4…...
rpc的原理
RPC(Remote Procedure Call,远程过程调用)是一种编程模型,它允许开发者像调用本地函数一样调用位于不同进程或者不同机器上的函数或服务。这种抽象简化了分布式系统的开发,使得开发人员无需关注底层网络通信细节&#…...

【无线通信发展史-第二篇】,带你走进查利·奥古斯丁·库仑的世界,了解(库伦定律)-(扭秤实验)-(如何测量出静电力常量)
前言:用这几个问答形式来解读下我这个系列的来龙去脉。如果大家觉得本篇文章不水的话希望帮忙点赞收藏加关注,你们的鼓舞是我继续更新的动力。 我为什么会写这个系列呢? 首先肯定是因为我本身就是一名从业通信者,想着更加了解自…...

CAPL使用结构体的方式组装一条DoIP车辆声明消息(方法2)
在文章CAPL使用结构体的方式组装一条DoIP车辆声明消息(方法1)中,我们声明一个结构体DoIPMessage表示完整的DoIP车辆声明消息: 上半部分是DoIP报头通用部分(也就是所有类型的DoIP消息都有的),而payload是每个类型的DoIP消息独有的部分,对于车辆声明消息来说,用另一个结…...
基于Matlab的车牌识别系统设计与实现
基于Matlab的车牌识别系统设计与实现 摘要 随着智能交通系统的不断演进,车牌识别技术已成为提升交通管理效率与准确性的关键。本文深入探讨了基于Matlab平台的车牌识别系统设计与实现,该系统通过精细的图像预处理、高效的车牌定位算法、精准的字符分割…...

使用Cisco进行模拟RIP路由协议配置
实验四 RIP路由协议配置 文章目录 实验四 RIP路由协议配置1.实验目的2.实验流程3.RIPv1实验步骤4.RIPv2实验步骤 1.实验目的 1)理解RIP路由的原理 2)掌握RIP路由的配置方法 2.实验流程 开始→布置拓扑→配置IP地址→配置并验证RIPv1→配置并验证RIPv2…...

段页式存储-系统架构师(三十七)
1、一个完整的系统需要从不同的角度进行描述,下图属于软件架构设计中的(),用于()视图来描述软件系统。 问题1 A对象图 B时序图 C构件图 D类图 问题2 A进程 B开发 C物理 D逻辑 解析: 从…...

通过指令深入了解Linux
文章目录 1.简单介绍XShell1.1下载安装XShell1.2 使用XShell登录主机1.3 XShell下的复制粘贴 2. Linux下的基本指令2.1 ls指令2.1.1 对文件的理解2.1.2 目录下的隐藏文件 2.2 pwd指令2.3 cd指令2.3.1 Linux下目录结构的认识 2.4 touch指令2.5 mkdir指令2.6 clear指令 1.简单介绍…...

IP探针双端源码
源码耗费两年半的制作过程 将源码上传至你的服务器或你的主机 可以对接其他东西或者网站其他语言 使用方法 1.参数使用 http://域名/sc.php?id这是生成端 http://域名/sc1.php?id这是生成端生成的链接可以跳转链接 http://域名/ck.php?id这是查看IP 生成端,生成完…...

高中数学学科知识与教学能力
梳理...

Flink 实时数仓(七)【DWS 层搭建(一)流量域汇总表创建】
前言 今天开始 DWS 层的搭建,不知不觉又是周一,都忘了昨天是周末,近两年对我来说,周六日晚上八九点能打一小会篮球就算一周的休息了。不得不说自己真的是天生打工体质,每天不管多累,晚上十二点睡࿰…...

Python和PyCharm的安装激活及Python新手入门指南
一、软件介绍 Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言。于 1989 年底由 Guido van Rossum 发明,第一个公开发行版发行于 1991 年。 当然也有很多小伙伴不清楚python与pycharm的区别和联系,接下来给大家简单介绍一下࿱…...
Apache Flink窗口机制解析:滚动窗口与滑动窗口的比较与应用
Apache Flink是一个开源的流处理框架,用于实现大规模数据流的处理和分析。在处理数据流时,窗口操作是一种常见的方法,它允许对数据流中连续的项目进行分组。Flink提供了多种窗口类型,其中滚动窗口(Tumbling Window&…...

为什么《程序员修炼之道》评分能到 9.1?
大家好,我是 方圆。开始接触到《程序员修炼之道:通向务实的最高境界》这本书是在豆瓣图书的高分榜单上,它的评分高达 9.1,其中有条蛮有意思的书评非常吸引我:“这本书我读过 5 遍信不信,每个字都磨出了感情…...
接口自动化测试框架中动态参数接口,加密接口,签名接口你们是怎么处理的?
动态参数:可通过热加载形式(在代码执行过中自动去yaml里面执行外部的函数) 接口测试加密解密简介: 对称加密(私钥加密,只有一个密钥)AES,DES,BASE64 特点是:加密和解密有相同的密钥…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践
在 Kubernetes 集群中,如何在保障应用高可用的同时有效地管理资源,一直是运维人员和开发者关注的重点。随着微服务架构的普及,集群内各个服务的负载波动日趋明显,传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...