Java实现栈结构

news2024/11/14 11:15:14

目录

一、栈概述

二、模拟实现栈 

1、入栈 

2、出栈 

3、取栈顶元素 

三、栈的应用

1、逆序打印链表

2、括号匹配问题 

3、逆波兰表达式求值

4、栈的压入、弹出序列

5、最小栈


一、栈概述

栈(Stack)也是数据结构的一种,属于线性数据结构,栈最大的特点是“先进后出”,就是先进入栈的元素后出来,栈只能每次弹出栈顶元素,不能弹出处在栈中间的元素。

二、模拟实现栈 

栈底层也是依据数组进行实现。

private int[] data;
private int usedSize;
public myStack(){
    this.data=new int[10];
}

1、入栈 

将元素入栈首先要判断栈是否已满,如果满了就要扩容,否则就直接将元素插入到栈中,栈的长度加1。

//入栈
    public void push(int val){
        if(isFull()){
            data= Arrays.copyOf(data,2*data.length);
        }
        data[usedSize++]=val;
    }
    //判断栈是否已满
    public boolean isFull(){
        if(usedSize==data.length){
            return false;
        }else{
            return true;
        }
    }

2、出栈 

出栈就首先需要判断栈是否为空,如果未空则无法取元素,否则就取出栈尾元素,栈长度减1。

//出栈
    public int pop(){
        if(isEmpty()){
            System.out.println("栈为空");
        }
       return data[--usedSize];
    }
    //判断栈是否为空
    public boolean isEmpty(){
        if(usedSize==0){
            return true;
        }
        return false;
    }

3、取栈顶元素 

与出栈不同,取栈顶元素只是拿到栈顶的元素,并不会让元素出栈,也需要判断栈是否为空。

//取栈顶元素
    public int peek(){
        if(isEmpty()){
            System.out.println("栈为空");
        }
        return data[usedSize-1];
    }

在Java标准库中也只实现了以上方法,但是在用Stack类时却有许多方法,因为Stack类继承了Vector类,Vector类本身也实现了许多方法。 

三、栈的应用

1、逆序打印链表

由于栈是先进后出的,所以就将链表中的元素全部入栈,再接着全部出栈。

//逆序打印链表
    public void printList(ListNode head){
        ListNode cur=head;
        Stack<Object> stack = new Stack<>();
        while(cur!=null){
            stack.push(cur.val);
            cur=cur.next;
        }
        while(!stack.empty()){
            System.out.println(stack.pop());
        }
    }

此处也可以通过递归来依靠链表直接打印。 

//递归实现逆序打印链表
    public void printList2(ListNode head){
        if(head==null){
            return;
        }else if(head.next==null){
            System.out.println(head.val);
        }else{
            printList(head.next);
            System.out.println(head.val);
        }
    }

2、括号匹配问题 

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 每个右括号都有一个对应的相同类型的左括号。

解题思路:可以遍历字符串,遇到左括号则入栈,遇到右括号则取栈顶元素进行匹配,若匹配失败则直接返回false,否则继续向下遍历,如果出现栈为空但是仍有右括号或栈不为空,但是字符串已经遍历完的情况也需要返回失败。

 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()){
                    char ch1=stack.peek();
                   if(ch1=='('&&ch==')'||ch1=='['&&ch==']'||ch1=='{'&&ch=='}'){
                        stack.pop();
                    }else{
                        return false;
                    }
                }else{
                    return false;
                }
            }
        }
        if(!stack.isEmpty()){
            return false;
        }
        return true;
    }

3、逆波兰表达式求值

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

逆波兰表达式也就是后缀表达式,我们通常使用的是中缀表达式,那么中缀表达式如何变成后缀表达式?

例如:

解题思路:由于本题给的就是一个后缀表达式,那么就不需要进行转换,可以通过遍历数组,如果是数字就入栈,如果是符号就弹出两个元素,分别作为左运算数和右运算数,因为-和/是要求运算顺序,然后将计算结果入栈,遍历完之后,栈中剩余的唯一元素就是表达式事务计算结果。

public int evalRPN(String[] tokens) {
        Stack<String > stack=new Stack<>();
        for(int i=0;i<tokens.length;i++){
            if(tokens[i].equals("+")||tokens[i].equals("-")||tokens[i].equals("*")||tokens[i].equals("/")
                    &&!stack.isEmpty()){
                int a=Integer.parseInt(stack.pop());
                int b=Integer.parseInt(stack.pop());
                int result=0;
                switch(tokens[i]){
                    case "+":
                        result=b+a;
                        break;
                    case "-":
                        result=b-a;
                        break;
                    case "*":
                        result=b*a;
                        break;
                    case "/":
                        result=b/a;
                        break;
                }
                stack.push(String.valueOf(result));
            }else{
                stack.push(tokens[i]);
            }
        }
        return Integer.parseInt(stack.pop());
    }

4、栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

解题思路:设置一个指针指向弹出序列的首个元素,将入栈序列的元素入栈,之后判断栈顶元素与指针所指的元素是否相同,若相同则指针后移,弹出栈顶元素,否则继续入栈,重复上述步骤,如果将入栈序列遍历完之后,栈不为空则返回false否则返回true。

public boolean IsPopOrder(int [] pushA,int [] popA) {
      Stack<Integer> stack=new Stack<>();
        int j=0;
        for(int i=0;i<pushA.length;i++){
            stack.push(pushA[i]);
            while(!stack.isEmpty()&&j<popA.length&&stack.peek().equals(popA[j])){
                stack.pop();
                j++;
            }
        }
        if(!stack.isEmpty()){
            return false;
        }
        return true;
    }

5、最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。

解题思路:在该问题中需要设置一个辅助栈minStack,

在插入元素时,如果minStack为空就直接插入,如果插入元素的值小于等于minStack的栈顶元素时就插入。

在删除栈顶元素时,如果minStack的栈顶元素与Stack的栈顶元素相同时也需要弹出。

在获取栈顶元素时,直接取Stack的栈顶元素。

在获取栈顶的最小元素时,则直接取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.isEmpty()){
            minStack.push(val);
        }else{
            if(val<=minStack.peek()){
                minStack.push(val);
            }
        }
    }

    public void pop() {
        if(!stack.isEmpty()){
            if(stack.pop().equals(minStack.peek())){
                minStack.pop();
            }
        }
    }

    public int top() {
        if(!stack.isEmpty()){
            return stack.peek();
        }
        return -1;
    }

    public int getMin() {
        return minStack.peek();
    }
}

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

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

相关文章

Usaco Training刷怪旅 第三层 第五题:Wormholes

美国人出的题真的难&#xff08;个人感觉&#xff09;&#xff0c;看起来还行&#xff0c;做起来就是另外一会儿事儿了 Farmer Johns hobby of conducting high-energy physics experiments on weekends has backfired, causing N wormholes (2 < N < 12, N even) to ma…

基于物体基元空间几何特征的移动激光雷达点云街道树提取与分割

paper题目&#xff1a;Street Tree Extraction and Segmentation from Mobile LiDAR Point Clouds Based on Spatial Geometric Features of Object Primitives Abstract 从移动光探测与测距(LiDAR)点云中提取行道树仍然面临挑战&#xff0c;如在复杂的城市环境中提取精度低、…

浅谈哨兵机制的原理

文章目录哨兵机制的基本流程监控:主观下线&#xff1a;客观下线&#xff1a;选主&#xff1a;筛选&#xff1a;打分&#xff1a;通知&#xff1a;哨兵机制的基本流程 哨兵其实就是一个运行在特殊模式下的 Redis 进程&#xff0c;主从库实例运行的同时&#xff0c;它也在运行。…

el-input中放入elbutton

如图&#xff0c;如何在element组建的el-input的后缀放一个可点击的按钮或者标签 <el-input><el-button style"padding-right:10px" slot"suffix" type"text" >选择</el-button></el-input>在el-input的官网介绍中&…

jina实现并发扩展的调研

基于之前对于clip-as-service的调研&#xff0c;我在官方文档中看到横向扩展页面中的副本相关内容&#xff0c;可以解决并发问题&#xff0c;于是动手验证了一番 参考链接 &#xff08;官方文档&#xff09;link 官方文档的描述 首先我整了一个服务端 如果需要开启副本&…

线段相交判断

一、问题描述已知两条线段P1P2和Q1Q2&#xff0c;判断P1P2和Q1Q2是否相交&#xff0c;若相交&#xff0c;求出交点。两条线段的位置关系可以分为三类&#xff1a;[1] 有重合部分;[2] 无重合部分但有交点;[3] 无交点。注意&#xff1a;这里讨论的是两条线段是否相交&#xff0c;…

典型相关分析(附SPSS操作)

典型相关分析&#xff1a;研究两组变量&#xff08;每个变量中都可能有多个指标&#xff09;之间相关关系的一种多元统计方法。他能够揭示出两组变量之间的内在联系。选能较为综合、全面的衡量所在组的内在规律。一组变量最简单的综合形式就是该组变量的线性组合。典型相关分析…

还在用破-解版Navicat?有款纯Web化SQL开发工具,免安装还免费

经常使用SQL工具的开发者对Navicat一定都不陌生。这款软件作为一款全球化的多数据库管理工具&#xff0c;这些年逐步得到全国各地SQLer&#xff08;SQL开发者&#xff09;的关注。 与其他很多外来的软件产品一样&#xff0c;由于价格原因&#xff0c;很多SQLer感觉不太适合适应…

Maven(通用结构,集合了测试、打包、发布功能为一体)

Maven基础&#xff1a; 作用&#xff1a; 1.提供一套标准化的项目结构&#xff08;用于例如idea导入到eclipse或其他软件中&#xff0c;项目结构不会紊乱&#xff09; 2.提供一套标准化构建流程&#xff08;编译、测试、打包、发布...&#xff09;&#xff08;右键Maven-run…

VS中的cmake

新建cmake项目要保证VS安装了SDK&#xff0c;这里是VS2019版本打开创建新项目——查找cmake——设置路径和项目名称新建项目下有三个文件&#xff1a;&#xff08;1&#xff09;与项目同名的cpp文件&#xff08;2&#xff09;与项目同名的h文件&#xff08;3&#xff09;cmake的…

Linux文件/文件夹权限详解

在Linux中&#xff0c;一个文件/文件夹的权限&#xff0c; 从文件/文件夹的归属来看&#xff0c;可以分为三类&#xff0c;一是文件/文件夹所有者权限、二是所有者所在的用户组权限、三是公共&#xff08;不限&#xff09;权限。 从文件本身的操作来看&#xff0c;也可以分为…

SpringBoot+VUE前后端分离项目学习笔记 - 【15 SpringBoot和Vue实现注册和异常处理】

前端代码 Header.vue 获取登录用户的昵称在Header进行显示&#xff0c;加入个人信息的路由 <template><div style"line-height: 60px; display: flex"><div style"flex: 1;"><span :class"collapseBtnClass" style"…

vue 父子组件通讯时执行的生命周期的顺序

Vue的生命周期 Vue的生命周期分为三个阶段&#xff1a;初始化阶段&#xff0c;更新数据阶段&#xff0c;销毁实例阶段 1&#xff0c;初始化阶段&#xff1a; beforeCreate()实例创建前&#xff1a;数据和模板均未获取到created()实例创建后&#xff1a;最早可以访问到data数…

sqlmap之绕过安全狗

sql注入不会绕过WAF&#xff1f;关注我&#xff0c;让我带你由简入难实战各个WAF&#xff0c;今天先来看看web安全渗透必会的安全狗WAF&#xff0c;你会绕吗&#xff1f;看我带你将它拿下 目录 一&#xff1a;环境配置 1.sqli-labs的sql注入靶场环境 2.安全狗waf软件 3.检测…

nrm使用详解

目录1. 什么是 nrm2. 安装 nrm3. 使用 nrm3.1 查看所有源列表3.2 切换源3.3 添加源3.4 删除源3.5 查看所有源的响应速率1. 什么是 nrm npm 的源管理器&#xff0c;切换下载安装 项目依赖 时的源地址。默认包含 npm yarn tencent cnpm taobao npmMirror&#xff0c;支持添加、删…

docker安装kafka

1.下载镜像 docker pull wurstmeister/kafka docker pull zookeeper:latest 2.启动镜像 1&#xff09;启动zookeeper docker run -d -p2181:2181 -v /etc/localtime:/etc/localtime --name zookeeper zookeeper:latest2)启动kafka docker run -d -p9092:9092 \-e KAFKA_ZO…

Twitter开发者账号申请

Twitter开发者账号申请 前期准备 Twitter绑定手机号 申请开发者账号要求绑定手机号&#xff0c;建议境外手机号&#xff0c;国内手机号容易出现收不到验证码的问题。一个可以正常使用的Twitter账号 被封的不可以。 开始注册 注册开发者管理平台账号 登录Twitter开发者管理…

STM32——ADC模数转换器

文章目录一、ADC模数转化器ADC简介逐次逼近型ADCADC框图二、ADC基本结构三、触发转换控制四、输入通道五、规则组的四种转换模式单次转换&#xff0c;非扫描模式连续转换&#xff0c;非扫描模式单次转换&#xff0c;扫描模式连续转换&#xff0c;扫描模式六、数据对齐七、转换时…

Linux系统下的rpm管理

文章目录Linux系统下的rpm管理1.介绍2.rpm包的简单查询指令3.rpm包的其它查询指今4.卸载rpm包5.安装rpm包Linux系统下的rpm管理 1.介绍 rpm用于互联网下载包的打包及安装工具&#xff0c;它包含在某些Linux分发版中。它生成具有.RPM扩展名的文件。RPM是RedHat Package Manage…

【设计篇】35 # 如何让可视化设计更加清晰?

说明 【跟月影学可视化】学习笔记。 分清信息主次&#xff0c;建立视觉层次 用醒目的颜色突出显示数据&#xff0c;把被淡化的其他视觉元素当作背景。 比如&#xff1a;平均温度与露点的散点例子 <!DOCTYPE html> <html lang"en"><head><m…