【左程云算法07】队列和栈-链表数组实现

目录

​编辑1)队列的介绍

核心操作

3)队列的链表实现和数组实现

使用数组实现队列

2)栈的介绍

核心操作

4)栈的数组实现

使用语言内置的实现

使用数组手动实现栈

5)环形队列的实现 leecode622

代码解析


视频链接
【算法讲解013【入门】队列和栈-链表、数组实现】

1)队列的介绍

先进先出。进了从尾进,从头出。

队列我们认为范围是左闭右开的。范围是[L,R),因此如果L<R,就说明有元素,如果L==R,说明队列里没有元素。

如果我们想加b到R位置,那么我们R++;(原来R在1位置)

如果我们想让数弹出,那么我们拿L位置的数,让L++

队列是一种遵循 先进先出 (First-In, First-Out, FIFO) 原则的线性数据结构。

可以把它想象成现实生活中的排队:最早来排队的人,最先获得服务并离开。在数据结构中,最早被放入(入队)的元素,也最先被取出(出队)。

核心操作

一个基本的队列通常支持以下几种操作:

  • offer(value) (或 enqueue): 将一个元素添加到队尾。

  • poll() (或 dequeue): 从队头取出一个元素,并将其从队列中移除。

  • peek() (或 head): 查看队头的元素,但不移除它。

  • isEmpty(): 判断队列是否为空。

  • size():返回队列中元素的个数。

3)队列的链表实现和数组实现

在很多语言中,都有现成的、基于链表实现的队列结构。例如在 Java 中,LinkedList 类就实现了 Queue 接口。

// 直接用Java内部的实现
// 其实内部就是双向链表,常数操作
public static class Queue1 {// java中的双向链表LinkedList就足够了public Queue<Integer> queue = new LinkedList<>();// 调用任何方法之前,先调用这个方法来判断队内是否有东西public boolean isEmpty() {return queue.isEmpty();}// 向队内加入num, 加到队尾public void offer(int num) {queue.offer(num);}// 从队头拿,从头拿public int poll() {return queue.poll();}
}

使用现成的 LinkedList 来实现队列非常简单,因为其双向链表的结构天然支持在头部和尾部进行 O(1) 复杂度的增删操作,完美契合队列的需求。

使用数组实现队列

在笔试和面试中,更常见的要求是让我们手动用数组来实现一个队列。这更能考察我们对数据结构底层实现的理解。

这是一个基础版的数组队列实现:

// 实际刷题时更常见的写法,常数时间好
// 如果可以确定加入操作的总次数不超过n,那么可以用
// 一般笔试、面试都会有一个明确数据量,所以这是最常用的方式
public static class Queue2 {public int[] queue;public int l; // 头指针public int r; // 尾指针// 加入操作的总次数上限是多少,一定要明确public Queue2(int n) {queue = new int[n];l = 0;r = 0;}// 调用任何方法之前,先调用这个方法来判断队内是否有东西public boolean isEmpty() {return l == r;}// 入队操作public void offer(int num) {queue[r++] = num;}// 出队操作public int poll() {return queue[l++];}// 查看队头public int head() {return queue[l];}// 查看队尾public int tail() {return queue[r - 1];}// 查看大小public int size() {return r - l;}
}

代码解析

  • 结构:我们用一个固定大小的数组 queue 作为容器,并设置两个指针:

    • l (left): 指向队头。下一个要被 poll 的元素就是 queue[l]。

    • r (right): 指向下一个可以插入元素的位置。下一个 offer 的元素将被放入 queue[r]。

  • isEmpty(): 当 l 和 r 指针相遇时 (l == r),说明队列中没有任何元素,队列为空。

  • offer(num): 将元素 num 放入 r 指向的位置,然后将 r 指针后移 (r++)。

  • poll(): 返回 l 指向的元素,然后将 l 指针后移 (l++)。

这种实现的局限性
这个基础版的数组队列有一个明显的问题:指针 l 和 r 只能单向地向右移动。这意味着,即使我们 poll 了很多元素,数组前面空出来的空间也无法被重新利用。当 r 到达数组末尾时,即使队列实际大小很小,我们也无法再 offer 新的元素了。

2)栈的介绍

像弹匣一样,装的时候放在上一个的上面弹出的时候也是上面的先弹出。先d再c等等。

和上面的队类似。

与队列的“先进先出”相反,栈是一种遵循 后进先出 (Last-In, First-Out, LIFO) 原则的线性数据结构。

它最经典的类比就是一摞盘子:我们总是把新盘子放在最上面,而取盘子时,也总是从最上面拿。最后放上去的盘子,最先被取走。

核心操作

一个基本的栈通常支持以下几种操作:

  • push(value): 将一个元素压入栈顶。

  • pop(): 从栈顶弹出一个元素,并将其从栈中移除。

  • peek(): 查看栈顶的元素,但不移除它。

  • isEmpty(): 判断栈是否为空。

  • size():返回栈中元素的个数。

4)栈的数组实现

使用语言内置的实现

Java 提供了 java.util.Stack 类,可以直接使用。它的底层是动态数组 (Vector)。

// 直接用Java内部的实现
// 其实就是动态数组,不过常数时间并不好
public static class Stack1 {public Stack<Integer> stack = new Stack<>();// 调用任何方法之前,先调用这个方法来判断栈内是否有东西public boolean isEmpty() {return stack.isEmpty();}public void push(int num) {stack.push(num);}public int pop() {return stack.pop();}public int peek() {return stack.peek();}public int size() {return stack.size();}
}

使用数组手动实现栈

这是在笔试、面试中考察的重点。我们通过一个数组和一个指针(或索引)来模拟栈的行为。

// 实际刷题时更常见的写法,常数时间好
// 如果可以保证同时在栈里的元素个数不超过n,那么可以用
// 也就是发生弹出操作之后,空间可以复用
// 一般笔试、面试都会有一个明确数据量,所以这是最常用的方式
public static class Stack2 {public int[] stack;public int size; // 指针,指向下一个可插入的位置// 同时在栈里的元素个数不超过npublic Stack2(int n) {stack = new int[n];size = 0;}// 调用任何方法之前,先调用这个方法来判断栈内是否有东西public boolean isEmpty() {return size == 0;}// 入栈public void push(int num) {stack[size++] = num;}// 出栈public int pop() {return stack[--size];}// 查看栈顶元素public int peek() {return stack[size - 1];}// 返回栈中元素数量public int size() {return size;}
}

代码解析

  • 结构:我们使用一个固定大小的数组 stack 和一个整型变量 size。这里的 size 非常巧妙,它既表示了栈中当前的元素数量,也同时扮演了栈顶指针的角色,指向下一个新元素应该被插入的位置。

  • isEmpty(): 当 size 为 0 时,栈为空。

  • push(num): 将新元素 num 放入 stack[size] 的位置,然后将 size 加一 (size++)。

  • pop(): 先将 size 减一 (--size),使其指向当前的栈顶元素,然后返回 stack[size]。注意,数据并没有从数组中被“清除”,但它已经变得不可访问,后续的 push 操作会覆盖它。这就是“空间复用”的体现。

  • peek(): 直接返回 stack[size - 1] 的值,因为 size - 1 正是当前栈顶元素的索引。

这种数组实现方式,所有操作的平均时间复杂度都是 O(1),性能非常好。

5)环形队列的实现 leecode622

举个例子,一共有五个位置,abcd依次放进去,a位置是头,d位置是尾,此时我想把a弹出,就像上文中的队列弹出,空间释放。头往后去。我再弹出个b接着我再加个e呢?

我要是再加个f呢?

但注意,c位置是头。

再加个g呢?

所以这就是个环形结构

所以只要你不同时多于5个在这个队列里,就能一直保持着环形队列继续下去。

那怎么写代码呢?

前提:size允许才能做操作一和操作二

这道题limit就是5

我现在要加入a

我再加个b,再加个c

弹出a

再加个d呢

再弹出b

再加个e

再加个f 放到尾巴的位置,这不就复用了吗?

https://leetcode.cn/problems/design-circular-queue/

// 设计循环队列
// 测试链接 : https://leetcode.cn/problems/design-circular-queue/
class MyCircularQueue {public int[] queue;public int l; // 头指针public int r; // 尾指针public int size; // 当前队列大小public int limit; // 队列容量// 构造器,设置队列长度为 kpublic MyCircularQueue(int k) {queue = new int[k];l = r = size = 0;limit = k;}// 向循环队列插入一个元素。如果成功插入则返回真public boolean enQueue(int value) {if (isFull()) {return false;} else {queue[r] = value;// r++, 结束了,跳回0r = r == limit - 1 ? 0 : (r + 1);size++;return true;}}// 从循环队列中删除一个元素。如果成功删除则返回真public boolean deQueue() {if (isEmpty()) {return false;} else {// l++, 结束了,跳回0l = l == limit - 1 ? 0 : (l + 1);size--;return true;}}// 从队首获取元素。如果队列为空,返回 -1public int Front() {if (isEmpty()) {return -1;} else {return queue[l];}}// 获取队尾元素。如果队列为空,返回 -1public int Rear() {if (isEmpty()) {return -1;} else {// r 指向的是下一个要插入的位置,所以队尾元素在 r 的前一个位置// 需要计算 r 的前一个位置,同样要考虑循环int last = r == 0 ? (limit - 1) : (r - 1);return queue[last];}}// 检查循环队列是否为空public boolean isEmpty() {return size == 0;}// 检查循环队列是否已满public boolean isFull() {return size == limit;}
}

代码解析

  • 成员变量

    • l 和 r:与之前一样,分别是头指针和尾指针。

    • limit:数组的总容量,即队列的容量上限。

    • size:核心变量。我们引入一个 size 变量来实时记录队列中元素的个数。这使得判断队列是“空”还是“满”变得极其简单,避免了复杂的指针位置判断。

  • enQueue(value) 入队

    1. 首先通过 isFull() 判断队列是否已满。

    2. queue[r] = value;:在尾指针 r 的位置放入新元素。

    3. r = r == limit - 1 ? 0 : (r + 1);:环形逻辑的关键。更新尾指针 r。如果 r 已经到达数组的最后一个位置 (limit - 1),则下一步就让它跳回到 0;否则,就正常 +1。

    4. size++:队列大小加一。

  • deQueue() 出队

    1. 首先通过 isEmpty() 判断队列是否为空。

    2. l = l == limit - 1 ? 0 : (l + 1);:环形逻辑的关键。更新头指针 l。与 r 的逻辑完全相同,如果 l 到达末尾,就跳回 0。

    3. size--:队列大小减一。

  • Front() 查看队头

    • 如果队列不为空,队头元素就是 l 指针指向的位置 queue[l]。

  • Rear() 查看队尾

    • 这是最需要注意的地方。因为 r 指向的是下一个将要插入的位置,所以真正的队尾元素在 r 的前一个位置。

    • int last = r == 0 ? (limit - 1) : (r - 1);:计算 r 的前一个位置,同样需要考虑环形。如果 r 当前在 0,那么它的前一个位置就是数组的末尾 limit - 1;否则,就是 r - 1。

    • 返回 queue[last] 即可。

  • isEmpty() 和 isFull()

    • 有了 size 变量,这两个判断变得无比清晰:size == 0 即为空,size == limit 即为满。

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

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

相关文章

Docker 清理完整指南:释放磁盘空间的最佳实践

前言 随着 Docker 使用时间的增长,系统中会积累大量的容器、镜像、数据卷和构建缓存,占用大量磁盘空间。本文将详细介绍如何有效清理 Docker 资源,释放磁盘空间,保持系统整洁。 Docker 资源类型 Docker 主要占用磁盘空间的资源包括: 容器 (Containers):运行中和已停止…

零基础快速了解掌握Linux防火墙-Iptables

一、 Iptables概述Iptables 是一个用户空间程序&#xff0c;可以用于设置和管理 Linux 操作系统的内核级防火墙。它通过表、链和 规则组成&#xff0c;可以灵活地根据不同的需求进行配置。iptables 具有以下特点&#xff1a;Iptables 作为内核级别的防火墙&#xff0c;具有高效…

12公里无人机图传模组:从模糊到超高清的飞跃,抗干扰能力全面升级

在无人机行业飞速发展的今天&#xff0c;高清图像传输已成为衡量无人机性能的重要标志之一。过去&#xff0c;无人机在长距离飞行时常常面临信号衰减、图像模糊&#xff0c;甚至数据丢失的问题&#xff0c;影响了用户的体验与应用效果。为了打破这一瓶颈&#xff0c;业内专家不…

从 “模板” 到 “场景”,用 C++ 磨透拓扑排序的实战逻辑

文章目录前言&#xff1a;《算法磨剑: 用C思考的艺术》 专栏《C&#xff1a;从代码到机器》 专栏《Linux系统探幽&#xff1a;从入门到内核》 专栏正文&#xff1a;[B3644 【模板】拓扑排序 / 家谱树](https://www.luogu.com.cn/problem/B3644)【解法】【参考代码】[P2712 摄像…

盲盒抽卡机小程序:从0到1的蜕变之路

盲盒抽卡机小程序从概念提出到最终上线&#xff0c;经历了从0到1的蜕变过程。这个过程充满了挑战与机遇&#xff0c;也凝聚了开发团队的智慧和汗水。本文将分享盲盒抽卡机小程序的开发历程&#xff0c;探讨其背后的技术实现和市场策略。需求分析&#xff1a;明确目标用户与市场…

分层-三层架构

文章目录介绍代码拆分Dao层server层controller层运行结果介绍 在我们进行程序设计以及程序开发时&#xff0c;尽可能让每一个接口、类、方法的职责更单一些&#xff08;单一职责原则&#xff09;。 单一职责原则&#xff1a;一个类或一个方法&#xff0c;就只做一件事情&#…

Vue2 VS Vue3

vue3 是的&#xff0c;Vue 3 确实取消了基于 JavaScript 原型的 Vue 和 VueComponent 构造函数&#xff08;即你提到的 vm 和 vc&#xff09;&#xff0c;取而代之的是一种完全不同的、基于普通对象和代理&#xff08;Proxy&#xff09;的实例管理方式。 这是一个颠覆性的改变…

Vue3入门到实战,最新版vue3+TypeScript前端开发教程,Vue3简介,笔记02

笔记02 一、Vue3简介 1.1、Vue3发布日期&#xff1a; 2020年9月18日 1.2、Vue3做了哪些升级&#xff1a; 1.2.1、性能的提升 官方发版地址&#xff1a;Release v3.0.0 One Piece vuejs/core 打包大小减少41%初次渲染快55%更新渲染快133%内容减少54% 1.2.2、源码的优化…

.net core webapi/mvc阿里云服务器部署 - 错误解决

错误及解决方案缺少web.config配置HTTP 错误 500.19 - Internal Server Error检查 IIS 配置1. 确保 .NET Core Hosting Bundle 已安装2. 检查 应用程序池 配置3. 检查 IIS MIME 类型检查文件权限1. 确保 IIS 用户 有权限访问网站目录2. 检查 web.config 文件权限启用详细错误日…

多输入(input)多输出(output)验证

#作者&#xff1a;程宏斌 文章目录前言Flb 1.9.4 INCLUDE配置测试测试方案测试配置文件测试命令Flb 3.0.2 INCLUDE配置测试测试方案测试配置文件启动命令结论结论一&#xff1a;结论二&#xff1a;前言 需要设计并执行一组测试用例&#xff0c;这些测试用例将包括以子文件形式…

行业学习【电商】:垂直电商如何理解?以专业宠物平台为例

声明&#xff1a;以下部分内容含AI生成 “宠物等爱好者的专业平台”指的是垂直电商的一个具体例子。 “垂直电商” 就是指不卖所有东西&#xff0c;只深耕某一个特定领域&#xff08;即“垂直”领域&#xff09;的电商平台。 “宠物爱好者的专业平台”就是这样一个专门为养宠…

GPT(Generative Pre-trained Transformer)模型架构与损失函数介绍

目录 一、核心架构&#xff1a;Transformer Decoder 1. 核心组件&#xff1a;仅解码器&#xff08;Decoder-Only&#xff09;的堆叠 2. 输入表示&#xff1a;Token 位置 3. 输出 二、训练过程&#xff1a;两阶段范式 阶段一&#xff1a;预训练&#xff08;Pre-training&…

GitHub 热榜项目 - 日榜(2025-09-10)

GitHub 热榜项目 - 日榜(2025-09-10) 生成于&#xff1a;2025-09-10 统计摘要 共发现热门项目&#xff1a;15 个 榜单类型&#xff1a;日榜 本期热点趋势总结 本期GitHub热榜呈现三大技术热点&#xff1a;LLM智能体应用爆发&#xff08;如parlant、AutoAgent&#xff09;&a…

论文阅读:arxiv 2023 Large Language Models are Not Stable Recommender Systems

总目录 大模型相关研究&#xff1a;https://blog.csdn.net/WhiffeYF/article/details/142132328 https://arxiv.org/pdf/2312.15746 速览 破解大语言模型在推荐系统中的不稳定性 该论文聚焦于大语言模型&#xff08;LLMs&#xff09;在推荐系统中的应用问题&#xff0c;指出…

Linux的使用——FinalShell下载使用及连接云服务器的教程

一、注册免费阿里云服务器 1. 进入阿里云服务器官网 阿里云-计算&#xff0c;为了无法计算的价值https://www.aliyun.com/?spm5176.ecscore_server.console-base_top-nav.dlogo.39144df5uvPLOm 2. 点击免费试用 这里我已经试用过了&#xff0c;大家选择合适的云服务器点击立…

如何清理 Docker 占用的巨大磁盘空间

我相信很多人在使用 Docker 一段时间后&#xff0c;都会遇到一个常见问题&#xff1a;磁盘空间被迅速吃光&#xff0c;尤其是在进行频繁的镜像构建、测试和运行容器时。以我自己为例&#xff0c;在 Ubuntu 24.04设备上&#xff0c;docker system df -v 一看&#xff0c;Docker …

【CMake】缓存变量

目录 一. 缓存变量 二.创建缓存变量 2.1.使用set()来创建缓存变量 2.2.使用FORCE参数来覆盖缓存变量 2.2.1.示例1——不带force的set是不能覆盖已经存在的缓存变量的 2.2.2.示例2——带force的set才能覆盖已经存在的缓存变量 2.2.3.对比示例 2.3.命令行 -D 创建/覆盖缓…

vue2使用若依框架动态新增tab页并存储之前的tab页的操作

1. 应用场景&#xff1a;点击历史记录&#xff0c;要比较两个tab页的内容时&#xff0c;需要做到切换tab页来回看左右对数据对比。2.开发难点若依项目正常是把路由配置到菜单管理里&#xff0c;都是设定好的。不过它也给我们写好了动态新增tab页的方&#xff0c;需要我们自己来…

论文阅读-SelectiveStereo

文章目录1 概述2 模块2.1 SelectiveIGEV和IGEV的差异2.2 上下文空间注意力2.2.1 通道注意力2.2.2 空间注意力2.3 SRU3 效果参考资料1 概述 本文主要结合代码对Selective的创新点进行针对性讲解&#xff0c;相关的背景知识可以参考我写的另两篇文章论文阅读-RaftStereo和论文阅…

深入分析神马 M56S+ 202T 矿机参数与性能特点

引言在比特币&#xff08;BTC&#xff09;和比特币现金&#xff08;BCH&#xff09;等主流加密货币的挖掘过程中&#xff0c;矿机的选择直接关系到挖矿的效率与收益。神马 M56S 202T矿机是SHA-256算法的矿机&#xff0c;凭借其强大的算力和高效的能效比&#xff0c;成为了矿工们…