【数据结构和算法】(基础篇三)——栈和队列
栈和队列
栈(Stack)和队列(Queue)是两种非常基本的数据结构,它们主要用于存储和检索元素。尽管它们都用于管理一组数据项,但它们的访问规则和数组都是不同的。
栈
栈是一种后进先出(Last In, First Out,LIFO)的数据结构。这意味着最后插入的元素将是第一个被删除的。在软件开发中,这种数据结构的特性还是经常被使用到的,比如浏览器的后退操作,撤销的操作总是最后执行的。递归的底层其实就使用了栈。
我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素称为空栈。栈又称为后进先出(Last In Filrst Out)的线性标,简称LlFO结构。
栈的特殊之处就在于限制了这个线性表的插入和删除位置,它始终只在栈顶进行。这也就使得栈底是固定的,最先进栈的只能在栈底。

顺序栈
用数组来实现栈,首先定义栈底和最初的栈顶在同一个位置,为-1,这样可以通过栈顶是否为-1判断是否为空栈。需要实现的功能有如下几个:初始化栈,传入最大值,使用最大值创建数组,用于数据的存储,初始化栈底和栈顶为-1;空栈和满栈判断;入栈和出栈操作;查看栈顶元素
public class mystack {private int size;private int top;private int array[];// 构造函数进行初始化public mystack(int maxSize) {size = maxSize; // 传入最大值top = -1; // 初始化toparray = new int[maxSize]; // 数组用来存储数据}// 判断空栈public boolean isEmpty(){return ( top == -1);}// 判断满栈public boolean isFull(){return ( top == size-1);}// 入栈操作public void pushStack(int num){//当前不是满栈才能入栈if (!isFull()){array[++top] = num; // top最开始是-1,要先++才能赋值System.out.println(num + "入栈成功");}else{System.out.println("栈已满,当前元素:"+num+"不能入栈");}}// 出栈操作public void getStack(){// 当前栈非空才能出栈if (!isEmpty()){int temp = array[top--];System.out.println(temp + "出栈成功");}else{System.out.println("栈已空");}}// 查看栈顶元素public void getPop(){// 非空if (!isEmpty()){System.out.println("当前栈顶元素为:"+array[top]);}else{System.out.println("栈已空");}}// 测试操作public static void main(String[] args) {mystack ms = new mystack(5);ms.pushStack(1);ms.pushStack(2);ms.pushStack(3);ms.pushStack(4);ms.pushStack(5);ms.getPop();ms.getStack();ms.getPop();}
}
链栈
顺序栈在每次创建栈的时候都需要提供最大值,扩容操作比较麻烦,使用链表的原理实现栈可以拥有更灵活的存储空间。但是顺序栈的存取定位更方便,如果整个栈的变化才可以预料的范围内,使用顺序栈更方便。两者各有优缺点,需要根据实际情况进行取用。
链栈的实现可以把top放在头节点,判断空栈就判断top是否为null即可;链栈的大小是弹性的,不需要对bottom和size进行限定,也不需要判断满栈
package dataStructure.stack;public class ListStack {private Node top;// 定义链表节点private static class Node{int data;Node next;public Node(int data) {this.data = data;this.next = null;}}// 构造函数初始化栈public ListStack() {top = null;}// 判断空栈public boolean isEmpty(){return (top == null);}// 入栈操作public void pushStack(Node node){node.next = top;top = node;System.out.println("节点:"+node.data+"成功入栈");}// 出栈操作public void getStack(){// 非空才能出栈if (!isEmpty()){System.out.println("节点:"+top.data+"出战成功");top = top.next;}else{System.out.println("栈已空");}}// 查看栈顶元素public void getPop(){// 非空才能出栈if (!isEmpty()){System.out.println("当前栈顶元素为:"+top.data);}else{System.out.println("栈已空");}}// 测试操作public static void main(String[] args) {ListStack ls = new ListStack();ls.pushStack(new Node(1));ls.pushStack(new Node(2));ls.pushStack(new Node(3));ls.pushStack(new Node(4));ls.pushStack(new Node(5));ls.getPop();ls.getStack();ls.getPop();}
}
java的封装
java已经为我们封装好了栈的数据结构,我们只需要在使用的时候调用即可,在java.util包中的Stack模块,其具体方法如下所示:
package dataStructure.stack;import java.util.Stack;public class JavaStack {public static void main(String[] args) {Stack<Integer> stack = new Stack<>();// 入栈stack.push(1);stack.push(2);stack.push(3);// 查看栈顶元素System.out.println("当前栈顶元素: " + stack.peek());// 出栈System.out.println("出栈元素: " + stack.pop());// 检查是否为空System.out.println("是否为空栈? " + stack.isEmpty());// 遍历栈中的所有元素System.out.println("栈中所有元素:");while (!stack.isEmpty()) {System.out.println(stack.pop());}}
}
队列
队列( queue ) 是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出( First In First Out) 的线性表,简称FIFO 。允许插入的一端称为队尾,允许删除的一端称为队头。

线性表有顺序存储和链式存储,栈是线性表,所以有这两种存储方式。同样,队列作为一种特殊的钱性表,也同样存在这两种存储方式。
循环队列
我们假设一个队列有n个元素,则顺序存储的队列需建立一个大于n的数组,并把队列的所有元素存储在数组的前n个单元,数组下标为0的一端即是队头。所谓的入队列操作,其实就是在队尾追加一个元素,不需要移动任何元素,因此时间复杂度为O(1)

与栈不同的是,队列元素的出列是在队头,即下标为0 的位置,那也就意味着,队列中的所有元素都得向前移动,以保证队列的队头,也就是下标为0的位置不为空,此时时间复杂度为O(n)

有一个好方法可以不用每次都移动所有数据,让操作变得简单,我们只需要将队头向后移动即可

为了避免当只有一个元素时,队头和队尾重合使处理变得麻烦,所以引入两个指针, front指针指向队头元素, rear指针指向队尾元素的下一个位置,这样当的front等于rear时,此队列不是还剩一个元素,而是空队列。
但是如果一直按照上面的操作进行的话,front和rear都会一直向后移动,这样的话数组多大都不够用,让rear超出数组的时候,我们可以让它回到0的位置进行循环,把之前空出的位置利用起来

这样的话又会有一个新问题,就是rear会再次与front重合,此时rear == front就表示队列满了,但是我们最开始的时候rear == front又表示空队列

解决的办法就是设置一个flag,当front == rear ,且flag = 0 时为队列空,当front == rear,且flag= 1时为队列满。办法二是当队列空时,条件就是front = rear,当队列满时,我们修改其条件,保留一个元素空间。也就是说,队列满时,数组中还有一个空闲单元。
因为rear既可能比front大,也可能比front小,第二种方法的具体计算公式是这样的:(rear+1) % QueueSize == front
package dataStructure.queue;// 用顺序表实现循环队列
public class CircularQueue {private final int capacity;private final int[] queue;private int front;private int rear;private int count;public CircularQueue(int capacity) {this.capacity = capacity;this.queue = new int[capacity];this.front = 0;this.rear = -1;this.count = 0;}// 入队操作public boolean enqueue(int value) {if (isFull()) {return false;}rear = (rear + 1) % capacity;queue[rear] = value;count++;return true;}// 出队操作public int dequeue() {if (isEmpty()) {throw new IllegalStateException("Queue is empty");}int removedValue = queue[front];front = (front + 1) % capacity;count--;return removedValue;}// 查看队首元素public int peek() {if (isEmpty()) {throw new IllegalStateException("Queue is empty");}return queue[front];}// 检查队列是否为空public boolean isEmpty() {return count == 0;}// 检查队列是否已满public boolean isFull() {return count == capacity;}// 测试代码public static void main(String[] args) {CircularQueue queue = new CircularQueue(5); // 创建一个容量为5的循环队列// 测试入队和出队操作for (int i = 0; i < 6; i++) {if (queue.enqueue(i)) {System.out.println(i + " enqueued");} else {System.out.println("Queue full, cannot enqueue " + i);}}while (!queue.isEmpty()) {System.out.println(queue.dequeue() + " dequeued");}// 尝试从空队列中出队try {System.out.println(queue.dequeue());} catch (IllegalStateException e) {System.out.println(e.getMessage());}}
}
链队列
队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已,我们把它简称为链队列。我们将头节点和尾节点设置为队头和队尾,这样就可以了。
package dataStructure.queue;// 用顺序表实现循环队列
public class LinkedListQueue {// 定义链表节点public static class Node{int data;Node next;public Node(int data) {this.data = data;this.next = null;}}private Node front;private Node rear;private int count;public LinkedListQueue() {this.front = null;this.rear = null;this.count = 0;}// 检查队列是否为空public boolean isEmpty() {return count == 0;}// 入队操作public void enqueue(Node newNode) {if (rear == null){ // 往空队列中添加数据front = newNode;rear = newNode;}else {rear.next = newNode;newNode.next = null;}count ++;System.out.println("数据"+ newNode.data+"入队成功");}// 出队操作public void dequeue() {if (count > 0) {System.out.println("数据"+ front.data+"出队成功");front = front.next;count --;}elseSystem.out.println("队列已空");}// 测试代码public static void main(String[] args) {LinkedListQueue lq = new LinkedListQueue();lq.enqueue(new Node(1));lq.enqueue(new Node(2));lq.enqueue(new Node(3));lq.enqueue(new Node(4));lq.enqueue(new Node(5));lq.dequeue();}
}
相关文章:
【数据结构和算法】(基础篇三)——栈和队列
栈和队列 栈(Stack)和队列(Queue)是两种非常基本的数据结构,它们主要用于存储和检索元素。尽管它们都用于管理一组数据项,但它们的访问规则和数组都是不同的。 栈 栈是一种后进先出(Last In,…...
Linux截图工具gsnap移植arm平台过程记录
Linux截图工具gsnap移植arm平台过程记录 最近工作中一款新产品开发接近尾声,需要写文档截图产品图形,找了一款开源的Linux截屏工具gsnap,将其移植到ARM产品中,这里记录一下移植过程。 gsnap 这个工具源代码就是一个C语言源文件&a…...
密码学知识点02
#来自ウルトラマンレオ(雷欧) 1 常见加密方式 2 对称加密 采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。 常见加密算法: DES : Data…...
实现Pytest测试用例按顺序循环执行多次
要实现测试用例按顺序循环执行多次,可以使用 pytest 的自定义装饰器或插件。这里有两种方法可以实现这个需求: 方法一:使用 pytest-repeat 插件 pytest-repeat 插件允许你重复执行测试用例。你可以使用 --count 参数来指定每个测试用例的执…...
SVN工作原理和使用示例
SVN(Subversion)是另一种版本控制系统,用于管理项目文件及其变更历史。与Git不同,SVN是集中式版本控制系统,这意味着所有版本控制操作都集中在一个中央服务器上。以下是SVN的工作原理和基本使用示例。 目录 SVN 工作…...
云服务器部署Java+Vue前后端分离项目
1、申请一个云服务器 选择云服务器:阿里云、腾讯云、百度云、京东云、华为云等等,我使用的是阿里云服务器。 2、远程链接服务器 使用FinalShell工具或者其他远程工具,使用SSH链接,主机地址要填写阿里云服务的公网ip,如…...
C++的7种设计模式原则
一、设计模式前言 设计模式(Design Patterns)的“模式”指的是一种在软件设计中经过验证的、解决特定问题的方案。它们不是具体的代码,而是解决常见设计问题的抽象方案或模板。设计模式提供了一种标准的方式来组织代码,以提高代码…...
24.8.5数据结构|栈
栈-弹夹 1、定义: 栈就是特殊的线性表,与之前的线性表的区别就是增加了约束,只允许在一端插入和删除,就这麽简单。 2、基本操作 栈的插入操作叫:入栈{进栈、压栈};栈的删除:出栈{退栈&#x…...
LeetCode算法题训练
力扣刷题训练 开始记录力扣的刷题之路 刷题思路来自灵茶山艾府 入门题单: 「新」动计划 编程入门编程基础 0 到 1 训练方法 A 滑动窗口(定长/不定长/多指针)二分算法(二分答案/最小化最大值/最大化最小值/第K小)…...
Python | Leetcode Python题解之第326题3的幂
题目: 题解: class Solution:def isPowerOfThree(self, n: int) -> bool:return n > 0 and 1162261467 % n 0...
手机CPU性能天梯图(2024年8月),含安兔兔/GB6/3DMark跑分
原文地址(高清无水印原图/持续更新/含榜单出处链接): 2024年8月手机处理器天梯图 2024年8月1日更新日志:由于近期并未有新处理器发布,故只做常规更新;移除鲁大师天梯图;补充其它天梯图数量。 -…...
通过实际的例子和代码演示,可以更好地理解 `optional` 的使用方式和应用场景
当然,让我们通过一些实际的例子来演示 std::optional 的使用方式和应用场景。 场景 1:函数返回值 假设我们有一个函数,它尝试从字符串中解析一个整数,但如果字符串不是一个有效的整数,我们希望返回一个错误状态。 #…...
Java 电商秒杀系统优化实战:实现进阶示例详解与 RabbitMQ 配置
上一篇博客介绍了使用消息队列、异步处理等技术构建 Java 电商秒杀系统的基本思路,本文将进一步优化代码实现,并提供更详细的代码示例和 RabbitMQ 配置,助您构建更健壮、高效的秒杀系统。 一、 代码优化 1. 接口限流 在 SeckillController…...
路径规划 | 基于狼群算法的无人机路径规划(Matlab)
目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 路径规划 | 基于狼群算法的无人机路径规划(Matlab) 狼是一种群居性动物,社会分工明确,通过承担各自的责任与团结协作,共同促进整个狼群的生存与发展。狼群算…...
13-python函数返回值和装包的后续提取数据方法——解包
1.1 参数解包 不定长参数简单来讲就是装包,把多个参数装到一个元组或者装到字典中,就叫做装包 Ctrld可以快速向下复制 传递实参时,也可以在序列类型的参数前添加星号,这样他会自动将序列中的元素依次作为参数传递 注意&#x…...
I. 对线
https://codeforces.com/gym/103186/problem/I 一开始感觉操作挺复杂的 但是写过Chino的数列 - 洛谷 发现可以通过矩阵来实现swap操作,就想能不能用线段树维护矩阵来写 有三排兵线,我们维护区间和,因此初始矩阵就有了 接下来分析每个操作的…...
Topsis法模型(评价类问题)
目录 本文章内容参考: 一. 概念 二. 特点和适用范围 三. 实现步骤 四. 代码实现 本文章内容参考: TOPSIS法模型讲解(附matlab和python代码) 【数学建模快速入门】数模加油站 江北_哔哩哔哩_bilibili 一. 概念 TOPSIS(Technique for O…...
HPA 与pod调度
HPA 自动更新工作负载资源(例如 Deployment 或者 StatefulSet), 目的是自动扩缩工作负载以满足需求。 绑定到deploy上,控制pod 依托于metrics-server HorizontalPodAutoscaler 水平pod自动扩缩:意味着对增加的负…...
jupyter下载
https://blog.csdn.net/qq_48372575/article/details/125630622 我下面是CPU运行的,GPU链接在上面 Anaconda下载 https://docs.anaconda.com/miniconda/miniconda-other-installer-links/ 参考链接: https://blog.csdn.net/qq_48372575/article/detai…...
蓝桥杯双周赛 第 16 场 小白入门赛 解题报告 | 珂学家 | 七夕娱乐场
前言 题解 因为这场七夕节,所以出的特别友好。 整体还是偏思维。 T6 额外提供组合数学解,还是蛮有趣的。 A. 喜鹊罢工 题型: 签到 365 可以有多少个 7 组成 365可以有多少个7组成 365可以有多少个7组成 向上取整即可 #include <iostream>usi…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
