数据结构-限定性线性表 - 栈与队列
栈和队列是数据结构中非常重要的两种限定性线性表,它们在实际应用中有着广泛的用途。这篇文章将深入讲解栈和队列的概念、抽象数据类型、实现方式、应用场景以及性能分析,并通过代码示例帮助大家更好地理解和实践。
一、栈的概念与抽象数据类型
1.1 栈的定义
栈(Stack)是一种特殊的线性表,它只允许在表的一端进行插入和删除操作。这个特殊的端称为栈顶(Top),而另一端称为栈底(Bottom)。栈的特点是后进先出(LIFO,Last In First Out)。
1.2 栈的抽象数据类型
栈的抽象数据类型(ADT)包括以下操作:
| 操作 | 描述 |
|---|---|
push(element) | 向栈顶插入一个元素 |
pop() | 从栈顶删除一个元素并返回该元素 |
peek() 或 top() | 查看栈顶元素而不删除 |
isEmpty() | 判断栈是否为空 |
isFull() | 判断栈是否已满(仅限固定大小栈) |
size() | 返回栈中元素的数量 |
1.3 栈的表示与实现
栈可以通过数组或链表实现。数组实现的栈称为顺序栈,链表实现的栈称为链栈。
顺序栈
顺序栈使用一个固定大小的数组来存储栈中的元素,并用一个指针(通常是一个整数)来指示栈顶的位置。
链栈
链栈使用链表来存储栈中的元素,栈顶对应链表的头节点。
1.4 栈的应用举例
-
括号匹配检查:检查括号是否正确匹配。
-
表达式求值:如中缀表达式转后缀表达式。
-
递归函数的实现:递归调用本质上使用了栈结构。
-
回溯算法:如迷宫求解。
1.5 栈的算法演示
以下是一个简单的括号匹配算法的树状图演示:
栈状态变化:
初始栈:空
输入字符:'(', 压栈 → 栈顶为 '('
输入字符:')', 弹栈 → 栈顶为空
最终栈为空 → 匹配成功
二、栈的代码实现
2.1 C语言实现
#include <stdio.h>
#include <stdlib.h>#define MAX_SIZE 100typedef struct {int[MAX data_SIZE];int top;
} Stack;void initStack(Stack *s) {s->top = -1;
}int isEmpty(Stack *s) {return s->top == -1;
}int isFull(Stack *s) {return s->top == MAX_SIZE - 1;
}void push(Stack *s, int value) {if (isFull(s)) {printf("Stack is full\n");return;}s->[++datas->top] = value;
}int pop(Stack *s) {if (isEmpty(s)) {printf("Stack is empty\n");exit(1);}return s->data[s->top--];
}int peek(Stack *s) {if (isEmpty(s)) {printf("Stack is empty\n");exit(1);}return s->data[s->top];
}int main() {Stack s;initStack(&s);push(&s, 10);push(&s, 20);printf("Top element: %d\n", peek(&s));printf("Popped element: %d\n", pop(&s));return 0;
}
2.2 C++实现
#include <iostream>
#include <vector>
using namespace std;class Stack {
private:vector<int> data;
public:void push(int value) {data.push_back(value);}void pop() {if (!isEmpty()) {data.pop_back();}}int top() {if (!isEmpty()) {return data.back();}throw "Stack is empty";}bool isEmpty() {return data.empty();}
};int main() {Stack s;s.push(10);s.push(20);cout << "Top element: " << s.top() << endl;s.pop();cout << "Top element after pop: " << s.top() << endl;return 0;
}
2.3 Java实现
import java.util.ArrayList;
import java.util.EmptyStackException;public class Stack {private ArrayList<Integer> data;public Stack() {data = new ArrayList<>();}public void push(int value) {data.add(value);}public int pop() {if (isEmpty()) {throw new EmptyStackException();}return data.remove(data.size() - 1);}public int peek() {if (isEmpty()) {throw new EmptyStackException();}return data.get(data.size() - 1);}public boolean isEmpty() {return data.isEmpty();}public static void main(String[] args) {Stack s = new Stack();s.push(10);s.push(20);System.out.println("Top element: " + s.peek());s.pop();System.out.println("Top element after pop: + " s.peek());}
}
2.4 Python实现
class Stack:def __init__(self):self.data = []def push(self, value):self.data.append(value)def pop(self):if self.is_empty():raise Exception("Stack is empty")return self.data.pop()def peek(self):if self.is_empty():raise Exception("Stack is empty")return self.data[-1]def is_empty(self):return len(self.data) == 0def size(self):return len(self.data)# 示例
s = Stack()
s.push(10)
s.push(20)
print("Top element:", s.peek())
print("Popped element:", s.pop())
三、队列的概念与抽象数据类型
3.1 队列的定义
队列(Queue)是一种特殊的线性表,它只允许在一端进行插入操作,在另一端进行删除操作。允许插入的一端称为队尾(Rear),允许删除的一端称为队头(Front)。队列的特点是先进先出(FIFO,First In First Out)。
3.2 队列的抽象数据类型
队列的抽象数据类型(ADT)包括以下操作:
| 操作 | 描述 |
|---|---|
enqueue(element) | 向队尾插入一个元素 |
dequeue() | 从队头删除一个元素并返回该元素 |
front() | 查看队头元素而不删除 |
isEmpty() | 判断队列是否为空 |
isFull() | 判断队列是否已满(仅限固定大小队列) |
size() | 返回队列中元素的数量 |
3.3 队列的表示与实现
队列可以通过数组或链表实现。数组实现的队列称为顺序队列,链表实现的队列称为链队列。
顺序队列
顺序队列使用一个固定大小的数组来存储队列中的元素,并用两个指针(front 和 rear)分别指示队头和队尾的位置。为了避免空间浪费,通常使用循环队列。
链队列
链队列使用链表来存储队列中的元素,队头对应链表的头节点,队尾对应链表的尾节点。
3.4 队列的应用举例
-
任务调度:如操作系统中的进程调度。
-
缓冲区管理:如打印机任务队列。
-
模拟场景:如银行排队系统。
-
广度优先搜索(BFS):图的遍历算法。
3.5 队列的算法演示
以下是一个简单的银行排队系统的树状图演示:
队列状态变化:
初始队列:空
客户A到达 → 队列变为 [A]
客户B到达 → 队列变为 [A, B]
客户A办理业务 → 队列变为 [B]
客户C到达 → 队列变为 [B, C]
客户B办理业务 → 队列变为 [C]
四、队列的代码实现
4.1 C语言实现
#include <stdio.h>
#include <stdlib.h>#define MAX_SIZE 100typedef struct {int data[MAX_SIZE];int front;int rear;
} Queue;void initQueueueue(Q *q) {q->front = 0;q->rear = 0;
}int isEmpty(Queue *q) {return q->front == q->rear;
}int isFull(Queue *q) {return (q->rear + 1) % MAX_SIZE == q->front;
}void enqueue(Queue *q, int value) {if (isFull(q)) {printf("Queue is full\n");return;}q->data[q->rear] = value;q->rear = (q->rear + 1) % MAX_SIZE;
}int dequeue(Queue *q) {if (isEmpty(q)) {printf("Queue is empty\n");exit(1);}int value = q->data[q->front];q->front = (q->front + 1) % MAX_SIZE;return value;
}int front(Queue *q) {if (isEmpty(q)) {printf("Queue is empty\n");exit(1);}return q->data[q->front];
}int main() {Queue q;initQueue(&q);enqueue(&q, 10);enqueue(&q, 20);printf("Front element: %d\n", front(&q));printf("Dequeued element: %d\n", dequeue(&q));return 0;
}
4.2 C++实现
#include <iostream>
#include <queue>
using namespace std;int main() {queue<int> q;q.push(10);q.push(20);cout << "Front element: " << q.front() << endl;q.pop();cout << "Front element after pop: " << q.front() << endl;return 0;
}
4.3 Java实现
import java.util.LinkedList;
import java.util.Queue;public class QueueExample {public static void main(String[] args) {Queue<Integer> q = new LinkedList<>();q.add(10);q.add(20);System.out.println("Front element: " + q.peek());q.remove();System.out.println("Front element after remove: " + q.peek());}
}
4.4 Python实现
from collections import dequeclass Queue:def __init__(self):self.data = deque()def enqueue(self, value):self.data.append(value)def dequeue(self):if self.is_empty():raise Exception("Queue is empty")return self.data.popleft()def front(self):if self.is_empty():raise Exception("Queue is empty")return self.data[0]def is_empty(self):return len(self.data) == 0def size(self):return len(self.data)# 示例
q = Queue()
q.enqueue(10)
q.enqueue(20)
print("Front element:", q.front())
print("Dequeued element:", q.dequeue())
五、栈与队列的性能分析与应用场景对比
5.1 时间性能分析
| 操作 | 栈 | 队列 |
|---|---|---|
| 插入(push/enqueue) | O(1) | O(1) |
| 删除(pop/dequeue) | O(1) | O(1) |
| 查看顶部/头部元素 | O(1) | O(1) |
5.2 空间性能分析
| 数据结构 | 空间复杂度 |
|---|---|
| 栈(顺序栈) | O(n) |
| 栈(链栈) | O(n) |
| 队列(顺序队列) | O(n) |
| 队列(链队列) | O(n) |
5.3 应用场景对比
| 应用场景 | 栈适用情况 | 队列适用情况 |
|---|---|---|
| 括号匹配 | ✓ | |
| 表达式求值 | ✓ | |
| 回溯算法 | ✓ | |
| 递归实现 | ✓ | |
| 任务调度 | ✓ | |
| 缓冲区管理 | ✓ | |
| 广度优先搜索(BFS) | ✓ | |
| 银行排队系统 | ✓ |
六、总结
栈和队列是两种非常重要的线性表结构,它们的主要区别在于元素的插入和删除操作的位置不同。栈遵循后进先出(LIFO)原则,而队列遵循先进先出(FIFO)原则。
-
栈:适合用于括号匹配、表达式求值、递归实现等场景。
-
队列:适合用于任务调度、缓冲区管理、广度优先搜索等场景。
两者的时间复杂度和空间复杂度都非常高效(均为O(1)和O(n)),但在不同应用场景中各有侧重。理解栈和队列的原理和实现,能够帮助我们在实际问题中选择合适的数据结构,提高程序的效率和可维护性。
希望这篇帖子能够帮助大家更好地理解和掌握栈与队列!如果有任何问题或建议,欢迎在评论区留言交流!
相关文章:
数据结构-限定性线性表 - 栈与队列
栈和队列是数据结构中非常重要的两种限定性线性表,它们在实际应用中有着广泛的用途。这篇文章将深入讲解栈和队列的概念、抽象数据类型、实现方式、应用场景以及性能分析,并通过代码示例帮助大家更好地理解和实践。 一、栈的概念与抽象数据类型 1.1 栈…...
详解如何复现DeepSeek R1:从零开始利用Python构建
DeepSeek R1 的整个训练过程,说白了就是在其基础模型(也就是 deepseek V3)之上,用各种不同的强化学习方法来“雕琢”它。 咱们从一个小小的本地运行的基础模型开始,一边跟着 DeepSeek R1 技术报告 的步骤,…...
Java集合框架 源码分析 迭代器 并发修改异常底层原理
迭代器 Java中的Iterator(迭代器)是集合框架中用于遍历容器元素的统一接口,提供了一种标准化的元素访问方式,无需依赖具体集合类型的实现细节。以下是其核心要点: 一、核心方法与使用步骤 获取迭代器 通过集合的 it…...
CentOS7更换国内YUM源和Docker简单应用
配置国内阿里云镜像源 ## 更新镜像源 # 1.备份 cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak# 2.替换镜像源文件 curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo# 3.生成缓存 yum clean all yum m…...
Cannot find module ‘vue‘ or its corresponding type declarations
在使用vue3vite创建新的工程时,在新增.vue文件时会出现Cannot find module vue这个错误。 只需要我们在项目中的.d.ts文件中添加以下代码即可 declare module *.vue {import { defineComponent } from vue;const component: ReturnType<typeof defineComponent&…...
【Python爬虫】详细工作流程以及组成部分
目录 一、Python爬虫的详细工作流程 确定起始网页 发送 HTTP 请求 解析 HTML 处理数据 跟踪链接 递归抓取 存储数据 二、Python爬虫的组成部分 请求模块 解析模块 数据处理模块 存储模块 调度模块 反爬虫处理模块 一、Python爬虫的详细工作流程 在进行网络爬虫工…...
欧拉服务器操作系统部署deekseep(Ollama+DeekSeep+open WebUI)
一、解压并安装 Ollama # 1. 解压文件(默认会得到一个二进制文件) tar -xzvf ollama-linux-amd64.tgz# 2. 将二进制文件安装到系统路径 sudo mv ollama /usr/local/bin/ sudo chmod x /usr/local/bin/ollama# 3. 验证安装 ollama --version链接…...
报错:Nlopt
报错:Nlopt CMake Error at TGH-Planner/fast_planner/bspline_opt/CMakeLists.txt:20 (find_package):By not providing "FindNLopt.cmake" in CMAKE_MODULE_PATH this project hasasked CMake to find a package configuration file provided by "…...
#4 我们为什么使用物联网? 以及 物联网的整体结构
设备不物联是否可以? 答案 是可以的,从项目实战的角度,还是有很多包括分拣,控制,检测等应用是分立的,这个和成本,场景,客户接受度等因素有关。 局部看,一些系统的确很简…...
centOS 安装和配置docker
以下是在 CentOS 系统上安装和配置 Docker 的详细步骤: 一、安装 Docker 1. 卸载旧版本(如有) sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate …...
3D版的VLA——从3D VLA、SpatialVLA到PointVLA(不动VLM,仅动作专家中加入3D数据)
前言 之前写这篇文章的时候,就想解读下3D VLA来着,但一直因为和团队并行开发具身项目,很多解读被各种延后 更是各种出差,比如从25年3月下旬至今,连续出差三轮,绕中国半圈,具身占八成 第一轮 …...
linux Shell编程之循环语句(三)
目录 一. for 循环语句 1. for语句的结构 2. for 语句应用示例 (1) 根据姓名列表批量添加用户 (2) 根据 IP 地址列表检查主机状态 二. 使用 while 循环语句 1. while 语句的结构 2. while 语句应用示例 (1) 批量添加规律编号的用户 (2) 猜价格游戏 三. until 循环语…...
C#容器源码分析 --- Queue<T>
Queue<T> 是 System.Collections.Generic 命名空间下的先进先出(FIFO)动态集合,其核心实现基于循环数组,通过维护头尾指针实现高效入队和出队操作。 .Net4.8 Queue<T>源码地址:queue.cs (microso…...
ViT 模型讲解
文章目录 一、模型的诞生背景1.1 背景1.2 ViT 的提出(2020年) 二、模型架构2.1 patch2.2 模型结构2.2.1 数据 shape 变化2.2.2 代码示例2.2.3 模型结构图 2.3 关于空间信息 三、实验3.1 主要实验3.2 消融实验 四、先验问题4.1 归纳偏置4.2 先验or大数据&…...
IntelliJ IDEA 中安装和使用通义灵码 AI 编程助手教程
随着人工智能技术的发展,AI 编程助手逐渐成为提升开发效率的强大工具。通义灵码是阿里云推出的一款 AI 编程助手,它能够帮助开发者实现智能代码补全、代码解释、生成单元测试等功能,极大地提升了编程效率和代码质量。 IntelliJ IDEA 是一款广…...
面向HPC平台应用的HBM电源完整性/信号完整性分析与设计方法
近年来,人工智能技术的爆发式增长推动大数据处理领域发生根本性变革,促使工业界转向基于大数据的工作模型。为应对海量数据处理的复杂问题,基于多边交互服务的数据中心不断涌现。此类应用被称为高性能计算(HPC)&#x…...
FreeRTOS入门与工程实践-基于STM32F103(一)(单片机程序设计模式,FreeRTOS源码概述,内存管理,任务管理,同步互斥与通信,队列,信号量)
裸机程序设计模式 裸机程序的设计模式可以分为:轮询、前后台、定时器驱动、基于状态机。前面三种方法都无法解决一个问题:假设有A、B两个都很耗时的函数,无法降低它们相互之间的影响。第4种方法可以解决这个问题,但是实践起来有难…...
can‘t set boot order in virtualbox
Boot order setting is ignored if UEFI is enabled https://forums.virtualbox.org/viewtopic.php?t99121 如果勾选EFI boot order就是灰色的 传统BIOS就是可选的 然后选中任意介质,通过右边的上下箭头调节顺序,最上面的应该是优先级最高的 然后就…...
2025年第十六届蓝桥杯省赛C++ A组真题
2025年第十六届蓝桥杯省赛C A组真题 1.说明2.题目A:寻找质数(5分)3.题目B:黑白棋(5分)4. 题目C:抽奖(10分)5. 题目D:红黑树(10分)6. 题…...
asp.net Kestrel 和iis区别
Kestrel 和 IIS 都是用于托管 Web 应用程序的服务器,不过它们在多个方面存在显著差异,下面为你详细分析: 1. 所属平台与跨平台能力 Kestrel:是.NET Core 及后续版本的一部分,具备跨平台特性,可在 Windows…...
《植物大战僵尸融合版v2.4.1》,塔防与创新融合的完美碰撞
《植物大战僵尸融合版》是基于经典塔防游戏《植物大战僵尸》的创意同人改版,由“蓝飘飘fly”等开发者主导制作。它在保留原版核心玩法的基础上,引入了独特的植物融合机制,玩家可以将不同的植物进行组合,创造出全新的植物种类&…...
SGP4 基于C、C++安装指南
简介:SGP4 是一个用于简化轨道摄动模型的开源项目。 依赖:GCC/CLang, CMake 下载:GitCode - 全球开发者的开源社区,开源代码托管平台 (https://gitcode.com/gh_mirrors/sg/sgp4)或者从我的资源下载 https…...
SBTI认证的意义,什么是SBTI认证,sbti科学碳目标的好处
SBTI认证的意义与科学碳目标(SBT)的好处 1. 什么是SBTI认证? SBTI(Science Based Targets initiative,科学碳目标倡议)是由全球环境信息研究中心(CDP)、联合国全球契约(…...
[LeetCode 1696] 跳跃游戏 6(Ⅵ)
题面: LeetCode 1696 数据范围: 1 ≤ n u m s . l e n g t h , k ≤ 1 0 5 1 \le nums.length, \ k \le 10^5 1≤nums.length, k≤105 − 1 0 4 ≤ n u m s [ i ] ≤ 1 0 4 -10^4 \le nums[i] \le 10^4 −104≤nums[i]≤104 思路 & Code 重点&…...
在思科模拟器show IP route 发现Gateway of last resort is not set没有设置最后的通道
如果在show ip route的时候出现没有设置最后的通道Gateway of last resort is not set Switch#show ip route Codes: C - connected, S - static, I - IGRP, R - RIP, M - mobile, B - BGPD - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter areaN1 - OSPF NSSA exte…...
Redis 常问知识
1.Redis 缓存穿透问题 缓存穿透:当请求的数据在缓存和数据库中不存在时,该请求就跳出我们使用缓存的架构(先从缓存找,再从数据库查找、这样就导致了一直去数据库中找),因为这个数据缓存中永远也不会存在。…...
履带小车+六轴机械臂(2)
本次介绍原理图部分 开发板部分,电源供电部分,六路舵机,PS2手柄接收器,HC-05蓝牙模块,蜂鸣器,串口,TB6612电机驱动模块,LDO线性稳压电路,按键部分 1、开发板部分 需要注…...
多卡集群 - Docker命令来启动一个容器的实例
一、Docker下载安装及相关配置 桌面版:Docker Desktop: The #1 Containerization Tool for Developers | Docker 服务器版:Install | Docker Docs 我们先以windows桌面版为例进行安装,一般在公司里会使用服务器版本,后期也会出一…...
测试第三课-------自动化测试相关
作者前言 🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂 🎂 作者介绍: 🎂🎂 🎂 🎉🎉🎉…...
【C++教程】进制转换的实现方法
在C中进行进制转换可以通过标准库函数或自定义算法实现。以下是两种常见场景的转换方法及示例代码: 一、使用C标准库函数 任意进制转十进制 #include <string> #include <iostream>int main() {std::string num "1A3F"; // 十六进制数int…...
