【Java数据结构】栈 (Stack)

news2024/11/29 9:49:39
【本节目标】
1. 栈的概念及使用
2. 相关 OJ

一、概念

  • :一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。
  • 栈中的数据元素遵守后进先出LIFOLast In First Out的原则。
  • 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
  • 出栈:栈的删除操作叫做出栈。出数据在栈顶 

栈在现实生活中的例子:

二、栈的使用

 

 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()); // 获取栈中有效元素个数---> 4
        System.out.println(s.peek()); // 获取栈顶元素---> 4
        s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
        System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
        if(s.empty()){
            System.out.println("栈空");
        }else{
            System.out.println(s.size());
        }
    }

三、栈的模拟实现

从上图中可以看到, Stack 继承了 Vector Vector ArrayList 类似,都是动态的顺序表,不同的是 Vector 是线程安全的。

import java.sql.Array;
import java.util.Arrays;

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

    public MyStack(int[] elem) {
        this.elem = new int[10];
    }
    
    public void push(int data){
        if(ifFull()){
            grow();
        }
        elem[usedSize++]=data;
    }
    public boolean ifFull(){
        return elem.length==usedSize;
    }
    private void grow(){
        elem= Arrays.copyOf(elem,elem.length*2);
        
    }
    public int pop(){
        if(isEmpty()){
            throw new  EmptyException("栈为空");
        }else {
            int k=usedSize-1;
            usedSize--;
            return elem[k];
        }
    }
    private boolean isEmpty(){
        return usedSize==0;
    }
    public int peek(){
        if(isEmpty()){
            throw new  EmptyException("栈为空");
        }else {
            return elem[usedSize-1];
        }
    }
}

四、栈的应用场景

1. 改变元素的序列

1. 若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()
A: 1,4,3,2                        B: 2,3,4,1                          C: 3,1,4,2                     D: 3,4,2,1
答案:C
2. 一个栈的初始状态为空。现将元素 1 2 3 4 5 A B C D E 依次入栈,然后再依次出栈,则元素出栈的顺序是( )。
A: 12345ABCDE            B: EDCBA54321              C: ABCDE12345           D: 54321EDCBA
答案:B

单链表是否可以实现栈?

答:

  • 顺序表实现的栈可以将插入、删除的时间复杂度达到O(1),
  • 如果采用尾插操作,入栈时间复杂度为O(N),如果有last那么时间复杂度为O(1),但是出栈一定是O(N)
  • 如果采用头插法,入栈时间复杂度为O(1),同时出栈的时间复杂度也是O(1)

结论:

  • 如果采用单链表来实现栈,那么可以采用头插法的形式来入栈和出栈,叫做链式栈
  • 采用双向链表来实现栈是完全ok的,入栈不管是头插还是尾插都可以实现,时间复杂度都可以达到O(1)

2. 将递归转化为循环

比如:逆序打印链表

{
    Stack<Node> s = new Stack<>();
    // 将链表中的结点保存在栈中
    Node cur = head;
    while(null != cur){
        s.push(cur);
        cur = cur.next;
        }
// 将栈中的元素出栈
        while(!s.empty()){
        System.out.print(s.pop().val + " ");
        }
   }

3. 括号匹配

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);
            //判断是否为左括号
            if(ch=='('||ch=='['||ch=='{'){
                stack.push(ch);//是左括号则入栈
            }else{
                if(stack.isEmpty()){
                    return false;//不是左括号,但是栈空,右括号多
                }
                char ch2=stack.peek();
                if((ch2=='('&&ch==')')||(ch2=='['&&ch==']')||(ch2=='{'&&ch=='}')){
                    stack.pop();//有括号刚好匹配左括号,出栈
                }else{
                    return false;//右括号不匹配左括号,错误
                }
            }
        }
        if(!stack.isEmpty()){
            return false;//遍历结束但是但是栈不空,左括号多
        }
        return true;
    }
}

4. 逆波兰表达式求值

题目:中缀表达式a+b*c+(d*e+f)*g,其转换成后缀表达式为abc*+de*f+g*+。

将表达式按照运算先后加括号

a+b*c+(d*e+f)*g=a+b*c+(d*e+f)*g

再将每个运算符移出对应的括号外面

a+b*c+(d*e+f)*g)=(abc*+(de*f)+g*+

class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack=new Stack<>();
        for(int i=0;i<tokens.length;i++){
            String ch=tokens[i];
            if(isOperator(ch)==false){
                int z=Integer.parseInt(ch);
                stack.push(z);
            }else{
                int y=stack.pop();
                int x=stack.pop();
                switch(ch){
                    case"+":stack.push(x+y);
                    break;
                    case"-" :stack.push(x-y);
                    break;
                    case"*" :stack.push(x*y);
                    break;
                    case"/":stack.push(x/y);
                    break;
                }
            }
        }
        return stack.pop();
    }
    private boolean isOperator(String ch){
        if(ch.equals("+")||ch.equals("-")||ch.equals("*")||ch.equals("/")){
            return true;
        }
        return false;
    }
}

把字符串变成整形的函数Integer.parseInt() 

5. 出栈入栈次序匹配

顺序遍历pushV,如果栈顶元素和popV当前元素相同,则弹出,不同则将pushV当前元素入栈

import java.util.*;
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pushV int整型一维数组 
     * @param popV int整型一维数组 
     * @return bool布尔型
     */
    public boolean IsPopOrder (int[] pushV, int[] popV) {
        // write code here
        Stack<Integer> stack=new Stack<>(); 
        int j=0;
        for(int i=0;i<pushV.length;i++){
                stack.push(pushV[i]);
                while(stack.empty()==false&&j<popV.length&&stack.peek()==popV[j]){
                        stack.pop();
                        j++;
                    }
                }
                 return stack.empty();
        }
}

6. 最小栈

入栈:

  • 普通栈一定要放
  • 最小栈放的原则:
    • 如果最小栈是空的,则放
    • 如果放的元素小于等于当前栈顶的元素,则放

出栈:判断出栈元素和最小栈栈顶元素关系,相同则最小栈也出去

import java.util.Stack;

class MinStack {

    public Stack<Integer> stack;
    public  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 {
            int peekVal = minStack.peek();
            if(val <= peekVal) {
                minStack.push(val);
            }
        }
    }
    public void pop() {
        if(stack.empty()) {
            return;
        }
        int popVal = stack.pop();
        if(popVal == minStack.peek()) {
            minStack.pop();
        }
    }
    
    public int top() {
        if(stack.empty()) {
            return -1;
        }
        return stack.peek();
    }
    
    public int getMin() {
        if(minStack.empty()) {
            return -1;
        }
        return minStack.peek();
    }
}

五、 概念区分

栈、虚拟机栈、栈帧有什么区别呢?
  • 栈:是一种数据结构
  • 虚拟机栈:是jvm中的一块内存
  • 栈帧:运行一个方法、一个函数时,给它开辟的内存

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

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

相关文章

C语言—单链表

目录 一、链表的概念及结构 二、单链表实现 &#xff08;2.1&#xff09;基本结构定义 &#xff08;2.2&#xff09;申请节点 &#xff08;2.3&#xff09;打印函数 &#xff08;2.4&#xff09;头部插入删除\尾部插入删除 &#xff08;2.4.1&#xff09;尾部插入 &…

Anaconda的安装与环境设置

文章目录 一、Anaconda介绍二、Anaconda环境搭建1. 下载Anaconda(1)官网下载(2)清华大学镜像 2. 安装Anaconda3.配置环境变量4.检验conda是否安装成功5.更改镜像源6.若菜单栏没有conda prompt 三、虚拟环境1.创建、查看、删除虚拟环境2.激活、退出虚拟环境 四、CUDA、Pytorch、…

基于SpringBoot+Vue的酒店客房管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

qemu-system-aarch64开启user用户模式网络连接

一、问题 在使用qemu构建arm64的虚拟机时&#xff0c;虚拟机没有网络&#xff0c;桥接方式相对麻烦&#xff0c;我只是需要联网更新即可。与宿主机的通信我使用共享文件夹即可满足要求。 使用指令启动虚拟机时&#xff0c;网络部分的参数为 -net user,hostfwdtcp::10022-:22 …

白板2-数学基础

高斯分布1-极大似然估计 高斯分布2-极大似然估计-无偏&有偏 高斯分布3-从概率密度角度高斯分布4-局限性高斯分布5-边缘概率及条件概率高斯分布6-求联合概率分布

八大排序--01冒泡排序

假设有一组数据 arr[]{2&#xff0c;0&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;7} 方法&#xff1a;开辟两个指针&#xff0c;指向如图&#xff0c;前后两两进行比较&#xff0c;大数据向后冒泡传递&#xff0c;小数据换到前面。 一次冒泡后&#xff0c;数组中最大…

codetop标签动态规划大全C++讲解(四)!!动态规划刷穿地心!!学吐了家人们o(╥﹏╥)o

一天复习一篇&#xff0c;个人学习记录 1.最大子数组和2.最长的斐波那契子序列的长度3.最大正方形4.最长有效括号5.乘积最大子数组6.可被三整除的最大和7.回文子串数目8.最长回文子序列9.最长回文子串 1.最大子数组和 给你一个整数数组 nums &#xff0c;请你找出一个具有最大…

SpringBoot在线教育平台:设计与实现的深度解析

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

【JAVA开源】基于Vue和SpringBoot的教学资源库系统

本文项目编号 T 067 &#xff0c;文末自助获取源码 \color{red}{T067&#xff0c;文末自助获取源码} T067&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析5.4 用例设计5.4.1 管…

654、最大二叉树

1、题目描述 . - 力扣&#xff08;LeetCode&#xff09; 其实就是给定了一个所谓"最大二叉树"的规则&#xff0c;让我们去构建二叉树。 以 nums [3,2,1,6,0,5] 为例&#xff0c;规则如下&#xff1a; (1)找出其中的最大值6将其作为根节点&#xff0c;6前面的是左子…

自动驾驶系列—线控系统:驱动自动驾驶的核心技术解读与应用指南

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

工具 | 红队大佬亲测5款推荐的Burpsuite插件

*免责声明&#xff1a;* *本文章仅用于信息安全技术分享&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作…

基于SpringBoot+Vue+MySQL的校园二手物品交易系统

系统展示 用户前台界面 管理员后台界面 系统背景 校园二手物品交易系统开发的背景与重要性随着高等教育的蓬勃发展&#xff0c;大学生群体的规模持续扩大&#xff0c;随之而来的是物品更新换代速度的显著加快。学生们在追求新潮、高品质生活的同时&#xff0c;往往会产生大量闲…

微信步数C++

题目&#xff1a; 样例解释&#xff1a; 【样例 #1 解释】 从 (1,1) 出发将走 2 步&#xff0c;从 (1,2) 出发将走 4 步&#xff0c;从 (1,3) 出发将走 4 步。 从 (2,1) 出发将走 2 步&#xff0c;从 (2,2) 出发将走 3 步&#xff0c;从 (2,3) 出发将走 3 步。 从 (3,1) 出发将…

llm接口高可用工程实践(尽快关注我,以后这些文章将只对粉丝开放)

上一节课程链接&#xff1a;中文llama3仿openai api实战-CSDN博客 &#xff0c;本文是在上一节基础上继续操作 课程介绍 本文基于Chinese-LLaMA-Alpaca-3&#xff08;https://github.com/ymcui/Chinese-LLaMA-Alpaca-3&#xff09;项目&#xff0c;介绍如何通过搭建2个llama3…

生信初学者教程(二十五):验证候选特征

文章目录 介绍加载R包导入数据函数重要特征的表达ROC分析汇总筛选结果输出结果总结介绍 在成功识别出核心特征之后,为了验证这些特征的有效性和可靠性,我们在发现数据集和验证数据集上进行了进一步的评估。这一步骤旨在确保这些特征在不同数据集上的表达值具有一致性,并验证…

大模型时代下小模型知多少?从模型结构、预训练数据到运行时成本分析总结

今天&#xff0c;我们来谈谈小模型。《Small Language Models综述&#xff0c;Small Language Models: Survey, Measurements, and Insights》&#xff1a;https://arxiv.org/pdf/2409.15790这个工作&#xff0c;会有一些启发。 本文主要介绍三个话题&#xff0c;一个是小模型…

【笔记】信度检验

一、信度 信度是指测量结果的一致性和稳定性。 1.一致性&#xff08;Consistency&#xff09; 一致性指的是测量工具内部各个部分或项目之间的协调一致程度。高一致性意味着测量工具的不同部分都在测量同一个概念或特质。 例子&#xff1a;智力测试 假设我们有一个包含100…

成为AI产品经理,应该具备哪些条件?

开篇勘误标题&#xff1a;未来不会有AI产品经理这个岗位&#xff0c;就像没有移动产品经理一样。 如果你是个产品经理&#xff0c;但是不懂移动端的产品交互和设计&#xff0c;那你就只能在自己的头衔前面加上一个“PC”&#xff1a;PC产品经理&#xff0c;代表你的细分或者不…

在线Html到Markdown转换器

具体请前往&#xff1a;在线Html转Markdown