【数据结构】_5.栈

news2024/9/29 7:20:15

目录

1. 概念

2. 栈的使用

2.1 方法

2.2 示例

3. 栈的模拟实现

4. 栈的应用场景

4.1 题目1:不可能的出栈序列

4.2 题目2:逆序打印单链表

4.3 题目3:逆波兰表达式求值

4.4 题目4:括号匹配

4.5 题目5:栈的压入、弹出训练

4.6 题目6:最小栈


1. 概念

(1)栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。

(2)进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。

(3)栈中的数据元素遵循后进先出的原则;

(4)压栈:栈的插入操作叫做进栈或压栈或入栈,入数据在栈顶;

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

2. 栈的使用

2.1 方法

方法功能
Stack()构造一个空栈
E push(E e)将e入栈并返回e
E pop()将栈顶元素出栈并返回
E peek()获取栈顶元素
int size()获取栈中有效元素个数
boolean empty()检测栈是否为空

2.2 示例

    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
        for(int i=0;i<=5;i++){
            stack.push(i);  // 压栈
        }
        // 获取栈顶元素
        System.out.println(stack.peek());
        Integer a = stack.pop();  // 出栈栈顶元素
        System.out.println(a);
        System.out.println(stack.peek());
        System.out.println(stack.size());
    }

3. 栈的模拟实现

Stack继承于Vector,查Vector源码可知vector内部用数组实现,故而模拟实现采用数组栈;

(1)包类关系:

(2)MyStack:

package TestMyStack;

import java.util.Arrays;

public class MyStack {
    public int[] elem;
    public int useSize;
    public MyStack(){
        this.elem = new int[10];
    }
    // 压栈
    public void push(int val){
        if(isFull()){
            // 扩容
            reSize();
        }
        elem[useSize] = val;
        this.useSize++;
    }
    // 判满
    public boolean isFull(){
        if(elem.length == this.useSize){
            return true;
        }
        return false;
    }
    // 扩容
    public void reSize(){
        elem = Arrays.copyOf(elem, 2*elem.length);
    }
    // 出栈并返回出栈元素
    public int pop(){
        if(isEmpty()){
            throw new EmptyException();
        }
//        int val = elem[this.useSize-1];
//        this.useSize--;
//        return val;
        return this.elem[--this.useSize];
    }
    // 判空
    public boolean isEmpty(){
        return this.useSize==0;
    }
    // 获取栈顶元素
    public int peek(){
        return this.elem[this.useSize-1];
    }
}

(3)EmptyException:

package TestMyStack;

public class EmptyException extends RuntimeException{
    public EmptyException(){

    }
}

4. 栈的应用场景

4.1 题目1:不可能的出栈序列

若进栈序列为1,2,3,4,进栈过程中可以出栈,则不可能的出栈序列是:C
A. 1,4,3,2   B. 2,3,4,1   C.3,1,4,2    D.3,4,2,1

4.2 题目2:逆序打印单链表

(1)单链表的递归逆序打印法:

 public void fun1(ListNode pHead){
        // 递归逆序打印单链表
        if(pHead == null){
            return;
        }
        if(pHead.next == null){
            System.out.println(pHead.val);
        }
        fun1(pHead.next);
        System.out.println(pHead.val);
    }

(2)单链表的循环递归逆序打印法:

public void fun2(ListNode pHead){
        Stack<ListNode> stack = new Stack<>();
        ListNode cur = head;
        while(cur!=null){
            stack.push(cur);
            cur = cur.next;
        }
        // 遍历栈
        while(!stack.isEmpty()){
            ListNode top = stack.pop();
            System.out.print(top.val+" ");
        }
        System.out.println();
    }

4.3 题目3:逆波兰表达式求值

题目链接:150. 逆波兰表达式求值 - 力扣(LeetCode)

解题思路:遍历后缀算数表达式数组,若为数据则入栈,若为算术运算符则出栈栈顶两元素分别作为后操作数和前操作数,再将计算结果入栈,继续向后遍历数组,循环操作,直至栈中仅有一个元素,就是最终值;

代码:

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

4.4 题目4:括号匹配

题目链接:20. 有效的括号 - 力扣(LeetCode)

代码:

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.empty()){
                    return false;  
                }
                //  第二种情况:栈不为空,判断是否匹配
                char ch2 = stack.peek();   //栈顶元素,必为左括号
                if(ch2 == '('&& ch == ')' || ch2 == '{' && ch == '}' || ch2 == '[' && ch == ']'){
                    stack.pop();
                }else{
                    return false;
                }
            }
        }
        if(!stack.empty()){
            return false;
        }
        return true;
    }
}

4.5 题目5:栈的压入、弹出训练

题目链接:栈的压入、弹出序列_牛客题霸_牛客网

解题思路:定义i下标遍历pushV,j下标遍历popV,将pushV的元素入栈,当二者元素不相等时,继续入栈pushV元素;当二者元素相等时,出栈栈顶元素,i和j均++;

代码:

import java.util.*;


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

4.6 题目6:最小栈

题目链接:155. 最小栈 - 力扣(LeetCode)

解题思路:为目标栈开辟一个储存最小值的栈,依次遍历目标栈,将最小的元素入栈最小栈,最小栈栈顶元素就是目标栈的最小元素,且能在常数时间内检索到最小元素;

代码:

class MinStack {
    private Stack<Integer> stack;
    private 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{   //minStack不为空
            if(val <= minStack.peek()){  
                // 如果要插入的值比minStack的栈顶元素小
                minStack.push(val); 
                // 注意当val==minStack栈顶元素时,也需要将该元素入栈minStack
                // 因为stack出栈元素时,如果该元素是minStack中的元素,该元素也需要出栈
                // 以保证在出栈stack最小元素时,minStack中的最小元素不受影响

            }
        }
    }
    
    public void pop() {
        if(!stack.empty()){
            Integer val = stack.pop();
            if(val.equals(minStack.peek())){
                minStack.pop();
            }
            // 如果对元素拆箱为int类型,就可使用==进行判等
        }
    }
    
    public int top() {
       if(!stack.empty()){
           return stack.peek();
       }
       return -1;
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

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

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

相关文章

如何构建高效的接口自动化测试框架

在选择接口测试自动化框架时&#xff0c;需要根据团队的技术栈和项目需求来综合考虑。对于测试团队来说&#xff0c;使用Python相关的测试框架更为便捷。无论选择哪种框架&#xff0c;重要的是确保 框架功能完备&#xff0c;易于维护和扩展&#xff0c;提高测试效率和准确性。今…

最适合新手的SpringBoot+SSM项目《苍穹外卖》实战—(五)员工管理

黑马程序员最新Java项目实战《苍穹外卖》&#xff0c;最适合新手的SpringBootSSM的企业级Java项目实战。 新增员工 设计 DTO 类 我们需要根据新增员工接口设计对应的 DTO 类去接收前端传递的参数&#xff0c;前端传递参数列表如下&#xff1a; 注意&#xff1a; 当前端提交的…

C++ 成员初始化列表和new运算符的应用

输出一个学生的学号&#xff0c;姓名&#xff0c;性别和出生年月日 class Date { public:Date(int y, int m, int d) :m_year(y), m_month(m), m_day(d) {}void Print(){cout << m_year << "/" << m_month << "/" << m_day…

第四章 No.1树状数组的原理与使用

文章目录 应用问题原理树状数组练习题241. 楼兰图腾242. 一个简单的整数问题243. 一个简单的整数问题2244. 谜一样的牛 线段树的反面&#xff1a;树状数组原理复杂&#xff0c;实现简单 应用问题 支持两个操作&#xff1a;快速求前缀和任意地修改某个数&#xff0c;时间复杂度…

520 · 一致性哈希 II

链接&#xff1a;LintCode 炼码 - ChatGPT&#xff01;更高效的学习体验&#xff01; 题解&#xff1a; class Solution{private:int n;const int mVirtualNodeCount;map<int, int> mVirtualNodeToMachineIdMap;set<int> mVirtualNodeSet;public:Solution(int n…

SpringBoot的三层架构以及IOCDI

目录 一、IOC&DI入门 二、三层架构 数据库访问层 业务逻辑层 控制层 一、IOC&DI入门 在软件开发中&#xff0c;IOC&#xff08;Inversion of Control&#xff09;和DI&#xff08;Dependency Injection&#xff09;是密切相关的概念。 IOC&#xff08;控制反转&a…

CAN学习笔记2:CAN简介

CAN 1 概述 CAN(Controller Area Network),是 ISO 国际标准化的串行通信协议,目的是适应汽车“减少线束的数量”、“通过多个网络进行大量数据的高速传输”的需求。 低速 CAN(ISO11519)通信速率 10~125Kbps&#xff0c;总线长度可达 1000米. 高速 CAN(ISO11898)通信速率 125~…

cnn卷积神经网络(基础)

convolutional neural networks 特征提取&#xff08;卷积、下采样&#xff09;->分类器 &#xff08;全连接&#xff09; 卷积过程 依次进行数乘 &#xff08;每个相同位置上的数字相乘再加和&#xff09; 左右数乘矩阵channel数量要一样&#xff0c;输出得到一个通道 卷…

吴师傅教你几招极速清理C盘,高能操作绝不让你失望!

电脑使用久了&#xff0c;C盘堆积的垃圾过多&#xff1b;每天上网会给电脑带来很多临时文件&#xff0c;这些垃圾文件不清理掉时间久了就会影响到电脑的运行速度&#xff1b;也会导致C盘变红&#xff0c;空间不足。那么&#xff0c;电脑C盘满了如何清理呢&#xff1f;教你几招极…

SpringBoot 如何进行 统一异常处理

在Spring Boot中&#xff0c;可以通过自定义异常处理器来实现统一异常处理。异常处理器能够捕获应用程序中抛出的各种异常&#xff0c;并提供相应的错误处理和响应。 Spring Boot提供了ControllerAdvice注解&#xff0c;它可以将一个类标记为全局异常处理器。全局异常处理器能…

NICE-SLAM: Neural Implicit Scalable Encoding for SLAM论文阅读

论文信息 标题&#xff1a;NICE-SLAM: Neural Implicit Scalable Encoding for SLAM 作者&#xff1a;Zihan Zhu&#xff0c; Songyou Peng&#xff0c;Viktor Larsson — Zhejiang University 来源&#xff1a;CVPR 代码&#xff1a;https://pengsongyou.github.io/nice-slam…

ARM单片机中断处理过程解析

前言 中断&#xff0c;在单片机开发中再常见不过了。当然对于中断的原理和执行流程都了然于胸&#xff0c;那么对于ARM单片机中断的具体处理行为&#xff0c;你真的搞清楚了吗&#xff1f; 今天来简单聊一聊&#xff0c;ARM单片机中断处理过程中的具体行为是什么样的&#xf…

spring5源码篇(13)——spring mvc无xml整合tomcat与父子容器的启动

spring-framework 版本&#xff1a;v5.3.19 文章目录 整合步骤实现原理ServletContainerInitializer与WebApplicationInitializer父容器的启动子容器的启动 相关面试题 整合步骤 试想这么一个场景。只用 spring mvc&#xff08;确切来说是spring-framework&#xff09;&#x…

Windows环境下安装及部署Nginx

一、安装Nginx教程 1、官网下载地址&#xff1a;https://nginx.org/en/download.html 2、下载教程&#xff1a;选择Stable version版本下载到本地 3、下载完成后&#xff0c;解压放入本地非中文的文件夹中&#xff1a; 4、启动nginx&#xff1a;双击nginx.exe&#xff0c;若双击…

Vue 3:玩一下web前端技术(五)

前言 本章内容为VUE语法的简单学习与相关语法讨论。 上一篇文章地址&#xff1a; Vue 3&#xff1a;玩一下web前端技术&#xff08;四&#xff09;_Lion King的博客-CSDN博客 下一篇文章地址&#xff1a; Vue 3&#xff1a;玩一下web前端技术&#xff08;六&#xff09;_L…

算法与数据结构(四)--排序算法

一.冒泡排序 原理图&#xff1a; 实现代码&#xff1a; /* 冒泡排序或者是沉底排序 *//* int arr[]: 排序目标数组,这里元素类型以整型为例; int len: 元素个数 */ void bubbleSort (elemType arr[], int len) {//为什么外循环小于len-1次&#xff1f;//考虑临界情况&#xf…

自动驾驶感知系统-全球卫星定位系统

卫星定位系统 车辆定位是让无人驾驶汽车获取自身确切位置的技术&#xff0c;在自动驾驶技术中定位担负着相当重要的职责。车辆自身定位信息获取的方式多样&#xff0c;涉及多种传感器类型与相关技术。自动驾驶汽车能够持续安全可靠运行的一个关键前提是车辆的定位系统必须实时…

为什么你的独立站有流量没转化?如何做诊断检查?

新店的创业初期&#xff0c;即使网站有流量&#xff0c;但是销售额为零的情况也常有发生。如果你确定流量是高质量的&#xff0c;寻找阻止潜在客户购买的具体因素可能会感到困难重重。 从“立即购买”按钮的色彩选择这样的细节&#xff0c;到构建品牌故事这样的大计划&#xf…

开发一个RISC-V上的操作系统(四)—— 内存管理

目录 往期文章传送门 一、内存管理简介 二、Linker Script 链接脚本 三、动态分配内存 四、测试 往期文章传送门 开发一个RISC-V上的操作系统&#xff08;一&#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统&#xff08;二…

springboot创建并配置环境(三) - 配置扩展属性(上集)

文章目录 一、介绍二、配置文件application.yml 一、介绍 在上一篇文章&#xff1a;springboot创建并配置环境(二) - 配置基础环境中&#xff0c;我们介绍了springboot如何配置基础环境变量。本篇文章讨论如何处理配置文件。即来自不同位置的配置属性&#xff0c;如&#xff1…