数据结构奇妙旅程之栈和队列

news2024/11/16 9:26:38

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱
ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶
个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
系列专栏:xiaoxie的JAVA系列专栏——CSDN博客●'ᴗ'σσணღ*
我的目标:"团团等我💪( ◡̀_◡́ ҂)" 

( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​+关注(互三必回)!

 一.栈(Stack)

1.概念

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈

顶,另一端称为栈底。栈中的数据元素遵守后进先出 LIFO Last In First Out )的原则。
压栈:栈的插入操作叫做进栈 / 压栈 / 入栈, 入数据在栈顶
出栈:栈的删除操作叫做出栈。 出数据在栈顶

2.栈的模拟实现

可以看出栈Stack 是继承与Vector的, Vector和ArrayList类似,我们可以得到以下的栈的模拟实现,帮助我们更好的理解栈的使用。

//这是栈内存储Integer的模拟,当然栈是泛型,这里只是Integer的模拟
class MyStack {
    public int[] arr;
    public int size;
    public MyStack() {
     arr = new int[10];
    }
    //入栈
    public int push(int e) {
        ensureCapacity();
        arr[size++] = e;
        return e;
    }
    //判断栈是否满
    private void ensureCapacity() {
        if (size == arr.length) {
            arr = Arrays.copyOf(arr, size * 2);
        }
    }
    //栈顶元素
    public int peek() {
        if(empty()) {
            System.out.println("栈为空,无元素");
            return -1;
        }
        return arr[size-1];
    }
    //出栈
    public int pop() {
        int tmp = peek();
        size--;
        return tmp;
    }
    //判断栈是否为空
    public boolean empty() {
        return this.size == 0;
    }

}

3.栈、虚拟机栈、栈帧有什么区别呢

栈、虚拟机栈和栈帧是计算机科学中的概念,它们之间有以下区别:

  1. 栈:栈是一种具有后进先出(Last-In-First-Out,LIFO)特性的数据结构,可以存储和检索数据。在计算机中,栈通常用于管理函数调用和局部变量的分配。栈在内存中是连续存储的一块区域,主要用于存储函数调用的上下文信息以及局部变量。

  2. 虚拟机栈:虚拟机栈是Java虚拟机(JVM)为每个线程分配的内存区域,用于存储方法的调用和执行信息。每个线程在执行方法时,都会在虚拟机栈中创建一个栈帧,栈帧中包含了方法的局部变量、操作数栈、方法返回地址等信息。

  3. 栈帧:栈帧是方法在虚拟机栈中的表示,用于存储方法的局部变量、操作数栈、方法返回地址等信息。每个方法在执行时,都会在虚拟机栈中创建一个对应的栈帧,方法的参数、局部变量以及中间计算结果都存储在栈帧中。当方法执行完毕后,对应的栈帧就会被销毁。

总结来说,栈是一种数据结构,用于存储和检索数据;虚拟机栈是Java虚拟机为每个线程分配的内存区域,用于存储方法的调用和执行信息;栈帧是方法在虚拟机栈中的表示,用于存储方法的局部变量、操作数栈、方法返回地址等信息。

 4.栈的应用

155.最小栈

 

题目分析:

我们都知道栈是一个先进后出的数据结构,所以我们只使用一个普通栈是无法实现最小栈,应该要用两个栈来模拟实现最小栈。

如果两个栈都为空就先将元素入栈

然后下一个元素先入stack 栈 之后和minstack 比较如果 < minstack的栈顶元素,就入 minstack 否则就不入,

这样就通过用两个普通栈模拟最小栈了

class MinStack {
     Stack<Integer> stack;
     Stack<Integer> minstack;
    public MinStack() {
        stack = new Stack<>();
        minstack = new Stack<>();
    }
    public void push(int val) {
        stack.push(val);
        if(minstack.empty()) {
            minstack.push(val);
        }else {
            if(minstack.peek() >= val) {
                minstack.push(val);
            }
        }
    }
    
    public void pop() {
        int tmp = stack.pop();
        if(tmp == minstack.peek()) {
            minstack.pop();
        }
    }
    
    public int top() {
      return stack.peek();
    }
    
    public int getMin() {
       return minstack.peek();
    }
}

 1.面试进阶

是否可以不用辅助栈呢

 栈中每个元素代表的是要压入元素与当前栈中最小值的差值 有个很重要问题: 在弹出时如何维护min? 因为每次压入新的元素时,压入的都是与当前栈中最小值的差值(还未压入当前元素),故在弹出元素时,若弹出了当前最小值,因为栈中记录了当前元素与【之前】最小值的差值,故根据这个记录可以更新弹出元素后的最小值。 接下来看代码吧

class MinStack {
    // 记录每个元素与【未压入】该元素时栈中最小元素的差值
    LinkedList<Long> stack;
    // 当前【已压入】栈中元素的最小值
    private long min;
    public MinStack() {
        stack = new LinkedList();
    }
    
    public void push(int val) {
        // 压入第一个元素
        if(stack.isEmpty()){
            min = val;
            stack.addFirst(0L);
            return;
        }
        // 栈不为空时,每次压入计算与min的差值后压入结果
        stack.push((long)val-min);
        // 更新min
        min = Math.min((long)val,min);
        // 上面两个语句是不能颠倒的!一定是先压入,在更新,因为min一定是当前栈中的最小值
    }
    
    public void pop() {
        long pop = stack.removeFirst();
        // 当弹出元素小于0时,说明弹出元素是当前栈中的最小值,要更新最小值
        if(pop<0){
            // 因为对于当前弹出的元素而言,计算压入栈中的值时,计算的是该元素与【未压入】该元素时
            // 栈中元素的最小值的差值,故弹出该元素后栈中的最小值就是未压入该元素时的最小值
            // 即当前元素的值(min)减去两者的差值
            long lastMin = min;
            min = lastMin - pop;
        }
        // 若大于等于0,不会对min有影响
    }
    
    public int top() {
        long peek = stack.peek();
        // 若当前栈顶小于等于0,说明最小值就是栈顶元素
        if(peek<=0) return (int)min;
        // 否则就是min+peek
        return (int)(min+peek);
    }
    
    public int getMin() {
        return (int)min;
    }
}

二.队列

1.概念

队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First
In First Out) 入队列:进行插入操作的一端称为 队尾( Tail/Rear 出队列:进行删除操作的一端称为 队头 Head/Front

2.队列的模拟实现

public class Queue {

    private int maxSize;
    private int[] queueArray;
    private int front;
    private int rear;
    private int nItems;

    public Queue(int size) {
        maxSize = size;
        queueArray = new int[maxSize];
        front = 0;
        rear = -1;
        nItems = 0;
    }

    public void insert(int value) {
        if (rear == maxSize - 1) {
            rear = -1;
        }
        queueArray[++rear] = value;
        nItems++;
    }

    public int remove() {
        int temp = queueArray[front++];
        if (front == maxSize) {
            front = 0;
        }
        nItems--;
        return temp;
    }

    public int peek() {
        return queueArray[front];
    }

    public boolean isEmpty() {
        return (nItems == 0);
    }

    public boolean isFull() {
        return (nItems == maxSize);
    }

    public int size() {
        return nItems;
    }

}
 

  三.面试题

 用队列实现栈

大家都清楚栈是先进后出,队列是先进先出的数据结构,如果要用队列模拟实现栈,仅靠一个队列是无法实现,需要用到两个队列,来模拟模拟实现栈

                                                                                                                                  

如果两个队列都为空 就入q1 的队

谁不为空就入队那个队列,如果要出栈的话,就把除了要出栈的那个元素之外的元素,入到另一个 队列中。

 代码如下

class MyStack {
   Queue<Integer> q1;
   Queue<Integer> q2;
    public MyStack() {
        q1 = new LinkedList<>();
        q2 = new LinkedList<>();
    }

    public void push(int x) {
        if(empty()) {
            q1.add(x);
            return;
        }if( ! q1.isEmpty()) {
            q1.add(x);
        }else {
            q2.add(x);
        }
    }

    public int pop() {
        if(empty()) return -1;
        if(!q1.isEmpty()) {
            int size1 = q1.size();
            for (int i = 0;i < size1-1;i++) {
                q2.add(q1.poll());
            }
            return q1.poll();
        }else {
            int size2 = q2.size();
            for (int i = 0; i < size2-1; i++) {
                q1.add(q2.poll());
            }
            return q2.poll();
        }
    }

    public int top() {
        if(empty()) {
            return -1;
        }int temp = -1;
        if(!q1.isEmpty()) {
            int size2 = q1.size();
            for(int i = 0; i < size2;i++) {
                temp = q1.poll();
                q2.offer(temp);
            }
            return temp;
        }else {
                 int size2 = q2.size();
                for(int i = 0;i < size2; i++) {
                   temp = q2.poll();
                   q1.offer(temp);
                }
            return temp;
        }
    }
    public boolean empty() {
        return q1.isEmpty() && q2.isEmpty();
    }
}

用栈实现队列

栈实现队列的出队操作效率低下:栈底元素(对应队首元素)无法直接删除,需要将上方所有元素出栈。

两个栈可实现将列表倒序:设有含三个元素的栈 A = [1,2,3] 和空栈 B = [] 。若循环执行 A 元素出栈并添加入栈 B ,直到栈 A 为空,则 A = [] , B = [3,2,1] ,即栈 B 元素为栈 A 元素倒序。

利用栈 B 删除队首元素:倒序后,B 执行出栈则相当于删除了 A 的栈底元素,即对应队首元素。

因此,可以设计栈 A 用于加入队尾操作,栈 B 用于将元素倒序,从而实现删除队首元素。

代码如下

class MyQueue {
    Stack<Integer> s1;
    Stack<Integer> s2;
    public MyQueue() {
        s1 = new Stack<>();
        s2 = new Stack<>();
    }
    public void push(int x) {
        s1.push(x);
    }
    public int pop() {
        if(s2.empty()) {
            while(!s1.empty()) {
                s2.push(s1.pop());
            }
        }
        return s2.pop();
    }
    public int peek() {
        if(s2.empty()){
            while(!s1.empty()){
                s2.push(s1.pop());
            }
        }
        return s2.peek();
    }
    public boolean empty() {
        return s1.empty() && s2.empty();
    }
}

以上就是栈和队列的所有内容了,在这里博主还是要说一句,要想理解栈和队列还是要多多刷类似的题目,一定可以更好的理解他们的使用

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

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

相关文章

Linux---重定向命令

1. 重定向命令的介绍 重定向也称为输出重定向&#xff0c;把在终端执行命令的结果保存到目标文件。 2. 重定向命令的使用 命令说明>如果文件存在会覆盖原有文件内容&#xff0c;相当于文件操作中的‘w’模式>>如果文件存在会追加写入文件末尾&#xff0c;相当于文件…

[C++] 虚函数、纯虚函数和虚析构(virtual)

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/weixin_43197380&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 Loewen丶原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&…

http正向代理测试,nginx反向代理中转正向代理服务器

有3台服务器如下&#xff1a; 192.168.111.201&#xff08;反向代理到正向代理服务器&#xff09; 192.168.111.202&#xff08;正向代理服务器&#xff09; 192.168.111.203&#xff08;目标WEB系统&#xff09; 防火墙网络策略如图所示: 1、192.168.111.200 只能访问 192.168…

【送书活动】智能汽车、自动驾驶、车联网的发展趋势和关键技术

文章目录 前言01 《智能汽车》推荐语 02 《SoC底层软件低功耗系统设计与实现》推荐语 03 《SoC设计指南》推荐语 05 《智能汽车网络安全权威指南&#xff08;上册&#xff09;》推荐语 06 《智能汽车网络安全权威指南&#xff08;下册&#xff09;》推荐语 后记赠书活动 前言 …

普通二叉树和右倾斜二叉树--LeetCode 111题《Minimum Depth of Binary Tree》

本文将以解释计算二叉树的最小深度的思路为例&#xff0c;致力于用简洁易懂的语言详细描述普通二叉树和右倾斜二叉树在计算最小深度时的区别。通过跟随作者了解右倾斜二叉树的概念以及其最小深度计算过程&#xff0c;读者也将对左倾斜二叉树有更深入的了解。这将为解决LeetCode…

FreeRTOS学习——同步互斥

FreeRTOS学习——同步互斥 目录 FreeRTOS学习——同步互斥一、概念1.1 同步1.2 互斥 二、示例——有缺陷的同步三、示例——优化有缺陷的同步四、示例——有缺陷的互斥五、总结 一、概念 1.1 同步 在FreeRTOS中&#xff0c;同步是指任务之间按照某种规则进行协调和按序执行的…

HarmonyOS:使用MindSpore Lite引擎进行模型推理

场景介绍 MindSpore Lite 是一款 AI 引擎&#xff0c;它提供了面向不同硬件设备 AI 模型推理的功能&#xff0c;目前已经在图像分类、目标识别、人脸识别、文字识别等应用中广泛使用。 本文介绍使用 MindSpore Lite 推理引擎进行模型推理的通用开发流程。 基本概念 在进行开…

PDI/Kettle-9.2.0.0-R(对应jdk1.8)源码编译问题记录及源码结构简介

目录 &#x1f4da;第一章 前言&#x1f4d7;背景&#x1f4d7;目的&#x1f4d7;总体方向 &#x1f4da;第二章 代码结构初识基本结构&#x1f4d7;代码模块详情 ⁉️问题记录❓问题一&#xff1a;代码分支哪些是发布版本❗答&#xff1a;后缀-R的版本 ❓问题二&#xff1a;50…

AI智能配音助手微信小程序前后端源码支持多种声音场景选择

大家好今天给大家带来一款配音小程序 &#xff0c;这款小程序支持多种不同声音和场景的选择更人性化&#xff0c; 比如说支持各地区的方言,英文,童声呀等等、 另外也支持男声女声的选择,反正就是模板那些非常的多 当然啦音量,语调,语速那些都是可以DIY跳转的哟,所以说这一款小程…

使用PyTorch II的新特性加快LLM推理速度

Pytorch团队提出了一种纯粹通过PyTorch新特性在的自下而上的优化LLM方法&#xff0c;包括: Torch.compile: PyTorch模型的编译器 GPU量化:通过降低精度操作来加速模型 推测解码:使用一个小的“草稿”模型来加速llm来预测一个大的“目标”模型的输出 张量并行:通过在多个设备…

【专题】最小生成树(prim算法、kruscal算法)

目录 一、最小生成树二、Prim算法1. 算法思想2. 例题3. 性能分析 三、Kruscal算法1. 算法思想2. 例题3. 性能分析 一、最小生成树 生成树中边的权值&#xff08;代价&#xff09;之和最小的树。 二、Prim算法 1. 算法思想 设N(V,{E})是连通网&#xff0c;TE是N上最小生成树…

【IEEE】2区SCI,接收领域广,稳定检索47年!

重点 本期推荐 区块链是一种新兴技术&#xff0c;很多行业和领域都以创新方式采用了此技术&#xff0c;如能源、金融、媒体和娱乐以及零售等。此外&#xff0c;区块链作为一门新兴的交叉学科, 涉及密码学应用&#xff08;加密&#xff0c;隐私等&#xff09;&#xff0c; 分布式…

stm32与Freertos入门(二)移植FreeRTOS到STM32中

简介 注意&#xff1a;FreeRTOS并不是实时操作系统&#xff0c;而是分时复用的&#xff0c;只不过切换频率很快&#xff0c;感觉上是同时在工作。本次使用的单片机型号为STM32F103C8T6,通过CubeMX快速移植。 一、CubeMX快速移植 1、选择芯片 打开CubeMX软件&#xff0c;进行…

Diva配置——Communication Tests

关联文章:CANoe.Diva生成测试用例 Diva目录 一、CANoe.Diva简介二、Communication Tests配置一、CANoe.Diva简介 CANoe.DiVa 是一种 CANoe 选项,用于对 ECU 中的诊断软件实施进行自动化测试。 可以通过CANdelaStudio制作的CDD或ODX文件,经过Diva配置自动生成测试用例和测试脚…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于时空注意力卷积模型的超短期风电功率预测》

这个标题描述了一种用于超短期风电功率预测的模型&#xff0c;该模型基于时空注意力卷积模型。下面我会逐步解读这个标题的关键词和背景&#xff1a; 超短期风电功率预测&#xff1a;风电功率预测是指根据历史风速和其他相关数据&#xff0c;通过建立数学模型来预测未来特定时间…

Vue学习计划-Vue2--VueCLi(四)组件传值和自定义事件

1. 组件传值 组件化编码流程&#xff1a; 拆分静态组件&#xff1a;组件要按照功能点拆分&#xff0c;命名不要与html元素冲突实现动态组件&#xff1a;考虑好数据的存放位置&#xff0c;数据是一个组件在用&#xff0c;还是一些组件在用&#xff1a; 一个组件在用&#xff0c…

云演ctf 你能看到我吗?

1、看题目稍微尝试不好用&#xff0c;看到提示的文件访问也不好用。读取文件又好像拦截了啥。 读取hint.php文件payload ctfphp://filter/convert.base64-encode/resourcehihintnt.php2、解密后又看到一个文件 有需要绕过 ctfphp://filter/convert.base64-encode/resource..…

轻量封装WebGPU渲染系统示例<45>- 材质组装流水线(MaterialPipeline)灯光、阴影、雾(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/MaterialPipelineFog.ts 当前示例运行效果: 此示例基于此渲染系统实现&#xff0c;当前示例TypeScript源码如下&#xff1a; export class MaterialPipelineFog {pr…

C语言数组刷题-----数组填充

输入一个整数 V &#xff0c;输出一个长度为 10 的数组 N &#xff0c;数组中的第一个元素为 V &#xff0c;每个后续元素的值都为上一个元素的值的 2 倍。 例如&#xff0c;如果输入整数为 1 &#xff0c;则数组为&#xff1a;1,2,4,8… 输入格式 输入一个整数 V 。输出格…

cmake多模块架构, DLL依赖编译

整体结构&#xff1a; 最外层的cmakelist CMakeLists.txt project(cmakeMulPackage) cmake_minimum_required(VERSION 3.17) set(CMAKE_CXX_STANDARD 11)#设置环境相关 message("set env.cmake") message("CMAKE_BUILD_TYPE is ${CMAKE_BUILD_TYPE}") …