数据结构——栈(Stack)详解

news2024/11/24 11:01:22

1. 栈(Stack)

1.1 概念

栈:一种特殊的线性表,只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中数据元素遵循后进先出LIFO(Last In First Out)的原则

压栈:栈的插入操作可以叫做进栈、压栈、入栈,入数据在栈顶

出栈:栈的删除操作叫做出栈,出数据在栈顶

1.2 栈的使用

方法功能
Stack()构造一个空的栈
E push(E e)将e入栈并返回e
E pop()将栈顶元素出栈并返回
E peek()获取栈顶元素
int size()获取栈中有效元素个数
boolean empty()检测栈是否为空
    public static void main(String[] args) {
        Stack<Integer> s = new Stack<>();
        s.push(1);
        s.push(2);
        s.push(3);
        s.push(4);
        System.out.println(s.size());//获取栈中有效数据
        System.out.println(s.peek());//查看栈顶元素
        System.out.println(s.pop());//使栈顶元素出栈
        System.out.println(s.empty());//检测栈是否为空
        System.out.println(s.isEmpty());//检测栈是否为空,继承自Vector
    }
System.out.println(s.isEmpty());

上面的isEmpty()方法,查看源码,虽然栈中没有,但是栈继承自Vector,在父类Vector中,有isEmpty方法

1.3 栈的模拟实现

import java.util.Arrays;

public class MyStack {
    public int[] elem;
    public int usedSize;

    public MyStack() {
        this.elem = new int[10];
    }

    public void push(int val) {
        if(isFull()) {
            //扩容
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        usedSize++;
    }

    public boolean isFull(){
        return usedSize == elem.length;
    }

    public int pop() {
        if(empty()) {
            return -1;
        }
        int oldVal = elem[usedSize-1];
        usedSize--;
        return oldVal;
    }

    public int peek() {
        if(empty()) {
            return -1;
        }
        return elem[usedSize-1];
    }
    public boolean empty() {
        return usedSize == 0;
    }
}

使用泛型实现

import java.util.Arrays;

public class MyStack<E> {
    public Object[] elem;
    public int usedSize;

    public MyStack() {
        this.elem = new Object[10];
    }

    public void push(E val) {
        if(isFull()) {
            //扩容
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        usedSize++;
    }

    public boolean isFull(){
        return usedSize == elem.length;
    }

    public E pop() {
        if(empty()) {
            return null;
        }
        E oldVal = (E)elem[usedSize-1];
        usedSize--;
        return oldVal;
    }

    public E peek() {
        if(empty()) {
            return null;
        }
        return (E)elem[usedSize-1];
    }
    public boolean empty() {
        return usedSize == 0;
    }
}

1.4 栈的应用场景

1.将递归转化为循环

    //递归方式
    public void printList(Node head) {
        if(null != head) {
            printList(head.next);
            System.out.println(head.val + " ");
        }
    }
    
    //运用栈的循环方式
    public void printList(Node head) {
        if(null == head) {
            return;
        }
        Stack<Node> s = new Stack<>();
        //将链表中的节点保存在栈中
        Node cur = head;
        while(null != cur) {
            s.push(cur);
            cur = cur.next;
        }
        
        //将栈中元素出栈
        while(!s.empty()) {
            System.out.println(s.pop().val + " ");
        }
    }

2. 括号匹配

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();//创建字符类型栈
        for(int i = 0; i < s.length(); i++) {//遍历字符串,将字符串中字符取出
            char ch = s.charAt(i);
            //1.遇到左括号,入栈
            if(ch == '(' || ch == '[' || ch == '{') {
                stack.push(ch);
            }else {
                //2.遇到右括号
                //先判断栈是否为空
                if(stack.empty()) {
                    return false;
                }else {
                    //3.取栈顶左括号看与当前右括号是否匹配
                    char chL = stack.peek();
                    if(chL == '(' && ch == ')' || chL == '[' && ch == ']' || chL == '{' && ch == '}') {
                        stack.pop();//若左右括号匹配,则栈顶元素出栈
                    }else {
                        return false;
                    }
                }
            }
        }
        return stack.empty();//最后若栈为空,返回true,栈不为空,返回false
    }
}

3. 逆波兰表达式求值

解析:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

  • 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
  • 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。

逆波兰表达式主要有以下两个优点:

  • 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
  • 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

将中缀表达式转换为后缀表达式的方法:

当逆波兰式运用到栈中,按照次序将数字入栈,若遇到运算符,则取出栈顶两个数字,先取出为运算符右边操作数,后取出为运算符左边操作数(这是为了避免当运算符为 - 或 / 时,顺序不同造成结果不同的问题),如下图:

代码:

    public int evalRPN(String[] tokens) {
        Stack<Integer> s = new Stack<>();
        for (int i = 0; i < tokens.length; i++) {
            String tmp = tokens[i];
            if(!isOpearation(tmp)) {//判断当前字符串是否为运算符
                Integer val = Integer.valueOf(tmp);//将字符串转换为数字
                s.push(val);
            }else {
                Integer val2 = s.pop();
                Integer val1 = s.pop();
                switch(tmp) {
                    case "+":
                        s.push(val1+val2);
                        break;
                    case "-":
                        s.push(val1-val2);
                        break;
                    case "*":
                        s.push(val1*val2);
                        break;
                    case "/":
                        s.push(val1/val2);
                        break;
                }
            }
        }
        return s.pop();
    }
    
    public boolean isOpearation(String s) {
        if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) {
            return true;
        }
        return false;
    }

4. 出栈入栈次序匹配

    public boolean IsPopOrder (int[] pushV, int[] popV) {
        // write code here
        Stack<Integer> s = new Stack<>();
        int count = 0;
        for(int i = 0; i < pushV.length; i++) {
            s.push(pushV[i]);
            //这个单独的循环,必须保证栈不为空,count不能越界,栈顶元素等于count下标处值
            while(!s.empty() && count != popV.length && s.peek() == popV[count]){
                s.pop();
                count++;
            }
        }
        return s.empty();
    }

5. 最小栈

class MinStack {
    Stack<Integer> s;//普通栈,泛型类型别忘记加!!!
    Stack<Integer> ms;//最小栈

    public MinStack() {//构造方法
        s = new Stack<>();
        ms = new Stack<>();
    }

    public void push(int val) {
        s.push(val);
        if(ms.empty()) {//若为第一次入栈操作,则最小栈无条件入栈
            ms.push(val);
        }else {
            Integer peekVal = ms.peek();//若不是第一次,则需与最小栈栈顶元素进行比较
            if(val <= peekVal) {
                ms.push(val);
            }
        }
    }

    public void pop() {
        if(s.empty()) {
            return;
        }
        int popVal = s.pop();//包装类属于引用类型,不能直接==,所以此处用int接收,自动拆箱
        if(popVal == ms.peek()) {
            ms.pop();
        }
    }

    public int top() {
        if(s.empty()) {
            return -1;
        }
        return s.peek();
    }

    public int getMin() {
        if(ms.empty()) {
            return -1;
        }
        return ms.peek();
    }
}

1.5 栈、虚拟机栈、栈帧的区别

栈(Stack):是一种只允许在一端进行插入或删除的线性表,满足后进先出的特点

虚拟机栈:逻辑结构,是具有特殊作用的一块内存空间,主管Java程序的运行,它保存方法的局部变量(8种基本数据类型、对象的引用地址)、部分结果,并参与方法的调用和返回

栈帧:函数从调用过程到结束的体现,一个函数从调用到销毁中占用的空间,内部的局部变量统一放在栈帧中。每个函数在运行时,JVM都会创建一个栈帧,然后将栈帧压入到虚拟机栈中,当函数调用结束时,该函数对应的栈帧会从虚拟机栈中出栈

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

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

相关文章

可再生能源的未来——Kompas.ai如何助力绿色发展

引言 在全球气候变化和能源危机的背景下&#xff0c;可再生能源逐渐成为能源发展的重要方向。本文将探讨可再生能源的发展趋势&#xff0c;并介绍Kompas.ai如何通过AI技术助力绿色发展的实现。 可再生能源的发展及其重要性 可再生能源是指通过自然资源产生的能源&#xff0c;…

Zabbix 7.0 新增功能亮点(二)——history.push API方法

Zabbix7.0LTS一经发布便吸引了众多运维小伙伴的关注&#xff0c;乐维社区forum.lwops.cn也伴随着不少小伙伴的热议与探讨&#xff0c;话不多说&#xff0c;抓紧上车。 前面我们介绍了zabbix 7.0 新增功能亮点&#xff08;一&#xff09;——T参数&#xff0c;本篇将向大家介绍z…

2024热门骨传导耳机购买推荐!精选五款好用不贵!

对于很多喜欢运动健身的小伙伴&#xff0c;在现在市面上这么多种类耳机的选择上&#xff0c;对于我来说的话还是很推荐大家去选择骨传导运动耳机的&#xff0c;相较于普通的入耳式蓝牙耳机&#xff0c;骨传导耳机是通过振动来传输声音的&#xff0c;而入耳式耳机则是通过空气传…

webstorm yarn环境配置

1. 安装nodejs https://nodejs.cn/download/ 2. 安装npm npm i yarn -g3.下载并安装webstorm https://www.jetbrains.com/webstorm/ 4. 打开settings确认node和yarn的配置正确5. 打开项目更新包 yarn install

酷开科技丨酷开系统智慧中心,解锁AI智能家居生活的无限可能

想象一下&#xff0c;未来的AI电视不再是冷冰冰的机器&#xff0c;而是家庭的智能伙伴。它学习你的喜好&#xff0c;预测你的需求&#xff0c;用声音和触感与你交流。它控制家中的灯光、温度&#xff0c;甚至帮你订购生活用品。 在探索智能家居的未来发展时&#xff0c;酷开系…

Rust 实战丨倒排索引

引言 倒排索引&#xff08;Inverted Index&#xff09;是一种索引数据结构&#xff0c;用于存储某个单词&#xff08;词项&#xff09;在一组文档中的所有出现情况的映射。它是搜索引擎执行快速全文搜索的核心技术&#xff0c;也广泛用于数据库中进行文本搜索。我们熟知的 Ela…

SpringBoot 大文件基于md5实现分片上传、断点续传、秒传

SpringBoot 大文件基于md5实现分片上传、断点续传、秒传 SpringBoot 大文件基于md5实现分片上传、断点续传、秒传前言1. 基本概念1.1 分片上传1.2 断点续传1.3 秒传1.4 分片上传的实现 2. 分片上传前端实现2.1 什么是WebUploader&#xff1f;功能特点接口说明事件APIHook 机制 …

休闲零食连锁迎来“万店”时代!“鸣鸣很忙”快速扩张有何秘诀?

6月12日&#xff0c;零食很忙与赵一鸣零食合并后的集团名称正式变更为“鸣鸣很忙”集团。目前&#xff0c;该集团旗下的双品牌全国门店总数已经突破10000家&#xff0c;标志着休闲零食连锁行业正式迎来“万店”时代。在激烈的市场竞争中&#xff0c;“鸣鸣很忙”以全国门店数第…

【Numpy】一文向您详细介绍 np.abs()

【Numpy】一文向您详细介绍 np.abs() 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本硕&#xff0c;曾…

rsa加签验签C#和js以及java互通

js实现rsa加签验签 https://github.com/kjur/jsrsasign 11.1.0版本 解压选择需要的版本&#xff0c;这里选择all版本了 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>JS RSA加签验签</title&g…

【Altium】AD-Fill、Region、Polygon之间的区别

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 Fill、Polygon、Region介绍&#xff0c;了解三者的区别。 2、 知识点 正片层、负片层&#xff0c;以及AD叠层管理中的设置。 3、软硬件环境 1&#xff09;、无关 2&#xff09;、无关 3&#xff09;、无关 4、…

动作识别综合指南

本文将概述当前动作识别&#xff08;action recognition&#xff09;的方法和途径。 为了展示动作识别任务的复杂性&#xff0c;我想举这个例子&#xff1a; 你能明白我在这里做什么吗&#xff1f;我想不能。至少你不会确定答案。我正在钻孔。 你能弄清楚我接下来要做什么吗&…

10. 安全性

这里写自定义目录标题 第10章 安全性10.1 安全性通用场景10.2 安全性策略不安全状态避免替代预测模型 不安全状态检测超时时间戳条件监测健全性检查比较 抑制冗余限制后果屏障 恢复 10.3基于策略的安全问卷10.4 安全性的模式10.5 扩展阅读10.6 问题讨论 第10章 安全性 吉尔斯&a…

GaN VCSEL:工艺革新引领精准波长控制新纪元

日本工程师们凭借精湛的技艺&#xff0c;开创了一种革命性的生产工艺&#xff0c;让VCSEL的制造达到了前所未有的高效与精准。这一成果由名城大学与国家先进工业科学技术研究所的精英们联手铸就&#xff0c;将氮化镓基VCSELs的商业化进程推向了新的高峰。它们将有望成为自适应前…

ArcGIS for js 4.x FeatureLayer 点选查询

示例&#xff1a; 代码如下&#xff1a; <template><view id"mapView"></view></template><script setup> import "arcgis/core/assets/esri/themes/light/main.css"; import Map from "arcgis/core/Map.js"; im…

【AI基础】第五步:纯天然保姆喂饭级-安装并运行chatglm3-6b

类似于 【AI基础】第三步&#xff1a;纯天然保姆喂饭级-安装并运行chatglm2-6b&#xff0c;有一些细节不一样。 此系列文章列表&#xff1a; 【AI基础】第一步&#xff1a;安装python开发环境-windows篇_下载安装ai环境python 【AI基础】第一步&#xff1a;安装python开发环境-…

五分钟看完WWDC24

大家好&#xff0c;我是小编阿文。欢迎您关注我们&#xff0c;经常分享有关Android出海&#xff0c;iOS出海&#xff0c;App市场政策实时更新&#xff0c;互金市场投放策略&#xff0c;最新互金新闻资讯等文章&#xff0c;期待与您共航世界之海。 北京时间6月11日凌晨1点&…

SylixOS下UDP组播测试程序

SylixOS下UDP组播测试 测试效果截图如下: udp组播发送测试程序。 /********************************************************************************************************* ** ** 中国软件开源组织 ** ** …

华为wlan实验

分为三步&#xff1a;1、网络互通&#xff0c;2、AP上线&#xff0c;3、wlan业务 1、网络互通 crow-sw: vlan batch 20 100 dhcp enable int vlan 20 ip add 192.168.20.1 24 dhcp select interfaceinterface GigabitEthernet0/0/2port link-type accessport default vlan 100…

构建 LLM 应用为什么需要文本加载器,langchain 中如何使用文本加载器?

构建 LLM 应用为什么需要文本加载器&#xff0c;langchain 中如何使用文本加载器&#xff1f; 上一篇文章中 [使用langchain搭建本地知识库系统(新) 我们构建一个 RAG 的本地应用&#xff0c;我们使用到了网页的文本加载器用来动态获取网页的数据。 在不同的应用场景中需要使…