栈的概念及应用

目录

一. 概念

二. 栈的使用

三. 栈的模拟实现

四. 栈的应用

1. 改变元素的序列

2. 将递归转化为循环

3. 括号匹配  链接

4. 逆波兰表达式求值 链接

5. 出栈入栈次序匹配 链接

6. 最小栈 链接


一. 概念

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

  

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

二. 栈的使用

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 ());
        }
}

三. 栈的模拟实现

可以用链表实现, 也可以用顺序表实现, 这里我们用顺序表:

public class MyStack {
    int[] array;
    int size;
    public MyStack(){
    array = new int[3];
    }
    public int push(int e){
        ensureCapacity();
        array[size++] = e;
        return e;
    }
    public int pop(){
        int e = peek();
        size--;
        return e;
    }
    public int peek(){
        if(empty()){
            throw new RuntimeException("栈为空,无法获取栈顶元素");
        }
        return array[size-1];
    }
    public int size(){
        return size;
    }
    public boolean empty(){
        return 0 == size;
    }
    private void ensureCapacity(){
        if(size == array.length){
            array = Arrays.copyOf(array, size*2);
        }
    }
}

四. 栈的应用

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
A:成立
B:成立
C:不成立
D:成立

2. 将递归转化为循环

比如:逆序打印链表
// 递归方式
void printList ( Node head ){
        if ( null != head ){
                printList ( head . next );
                System . out . print ( head . val + " " );
        }
}
// 循环方式
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 . print ( s . pop (). val + " " );
        }
}

3. 括号匹配  链接

思路:

1. 先遍历字符串, 如果遇到左括号( { [ , 就压入栈中, 如果遇到右括号) } ], 就需要判断:

        1) 如果此时栈为空, 说明没有和右括号匹配的左括号, 所以括号匹配失败

        2)如果栈不为空, 那么判断栈顶元素是否和此时的字符相匹配, 如果匹配则出栈

2. 如果字符串遍历完成, 但此时栈中还有元素, 意味着左括号剩余, 则匹配失败

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

               }
            }
        }
        if(!stack.isEmpty()){
            return false;
        }
        return true;

    }
}

4. 逆波兰表达式求值 链接

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

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

 中缀表达式如果转成后缀表达式:

1. 将每一次计算都加上括号 例:(( 1 + 2 ) * ( 3 + 4 )) 

2. 将括号中的符号移到括号后 例: (( 1 2 )+( 3 4 )+) *

3. 把括号删去 例: 1 2 + 3 4 + *

逆波兰表达式如何求值:

1. 手动: 从前往后遍历字符串, 遇到运算符就取此运算符的前两个数字计算, 计算的值替换掉原来的位置一步一步运算即可

例:  1 2 + 3 4 + *

第一步:1+2 = 3  替换: 3 3 4 + *

第二步: 3+4 = 7 替换: 3 7 *

第三步: 3*7= 21

2. 代码:使用栈这种数据结构, 从前往后遍历字符串, 遇到数字就入栈, 遇到运算符就弹出两个数字并进行计算, 将结果再压入栈中

class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        for(int i=0;i<tokens.length;i++){
            String str = tokens[i];
          if(!isOperations(str)){
              int val = Integer.valueOf(str);
              stack.push(val);

          }else{
              int num2 = stack.pop();
              int num1 = stack.pop();
              switch(str) {
                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 isOperations(String str){
        if(str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/") ){
            return true;
        }
        return false;

    }
}

5. 出栈入栈次序匹配 链接

思路:

给出两个数组, 数组pushV是入栈顺序, 数组popV是出栈顺序, 我们需要同时遍历两个数组, 将pushV中的数据压入栈中, 每放一次, 都要循环判断popV中的数字与栈顶元素是否相同, 如果相同则出栈, 数组popV向后遍历,不同则继续入栈, 最后当两个数组全部遍历完成, 则说明顺序是匹配的, 否则是不匹配的

代码:

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

6. 最小栈 链接

思路:

1. 要想在常数时间检索到最小的数字, 需要借助两个栈, 一个普通栈存放所有的元素, 另一个最小栈存放压栈时的最小数字

2. 当入栈时, 要先和最小栈中的栈顶元素进行比较, 如果最小栈为空, 则直接存放在最小栈, 如果大于栈顶元素, 不放, 如果小于等于栈顶元素, 放

3. 当出栈时, 需从普通栈出栈, 如果最小栈的栈顶元素和要出栈的数字相同, 则最小栈也需要出栈

代码:

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{
            int peekNum = minStack.peek();
            if(val <= peekNum){
                minStack.push(val);
            }
        }

    }
    
    public void pop() {
        int popNum = stack.pop();
        if(popNum == minStack.peek()){
            minStack.pop();
        }

    }
    
    public int top() {
        return stack.peek();

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

    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

书生·浦语大模型图文对话Demo搭建

前言 本节我们先来搭建几个Demo来感受一下书生浦语大模型 InternLM-Chat-7B 智能对话 Demo 我们将使用 InternStudio 中的 A100(1/4) 机器和 InternLM-Chat-7B 模型部署一个智能对话 Demo 环境准备 在 InternStudio 平台中选择 A100(1/4) 的配置&#xff0c;如下图所示镜像…

使用Docker部署Nacos集群和Nginx高可用负载(9节点集群部署)

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容部署Nacos集群Nginx高可用负载 &#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专…

C#,动态规划(DP)N皇后问题(N Queen Problem)的回溯(Backtracking)算法与源代码

1 N皇后问题&#xff08;N Queen Problem&#xff09; 在N*N的方格棋盘放置了N个皇后&#xff0c;使得它们不相互攻击&#xff08;即任意2个皇后不允许处在同一排&#xff0c;同一列&#xff0c;也不允许处在与棋盘边框成45角的斜线上。 2 回溯算法 回溯算法实际上一个类似枚…

我把steam游戏搬砖当副业,一个月赚7K+想给有梦想的人提个醒

假如你不工作了&#xff0c;还有收入吗&#xff1f;去掉日常的开销&#xff0c;还剩多少呢&#xff1f;可以靠steam游戏搬砖项目翻身吗&#xff1f;总以为&#xff0c;只要卖力工作&#xff0c;努力赚钱&#xff0c;就能实现财富自由。殊不知&#xff0c; 你的死工资&#xff0…

如何在Linux Ubuntu系统使用Docker快速部署MongoDB并公网访问

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主要介绍如何在Linux Ubuntu系统使用Docker快速部署Mon…

TypeScript 用起来真是太痛苦了

此前我写了几篇文章&#xff0c;关于 Electron&#xff0c;关于 Vue&#xff0c;创建项目的时候&#xff0c;我都默认选择了使用 TypeScript 的模板&#xff0c;不过我都加了一句话&#xff0c;初学者如果不想自己找麻烦的话&#xff0c;最好不要使用 TypeScript。原因呢&#…

QT-Day5

思维导图 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);if(!db.contains("stuInfo.db")){//说明数据库不存在db QSqlDatabase::addDatabase("…

TikTok矩阵系统的功能展示:深入解析与源代码分享!

今天我来和大家说说TikTok矩阵系统&#xff0c;在当今数字化时代&#xff0c;社交媒体平台已成为人们获取信息、交流思想和娱乐放松的重要渠道&#xff0c;其中&#xff0c;TikTok作为一款全球知名的短视频社交平台&#xff0c;凭借其独特的创意内容和强大的算法推荐系统&#…

20. 【Linux教程】emacs 编辑器

前面小节介绍了如何使用 vim 编辑器和 nano 编辑器&#xff0c;本小节介绍 emacs 编辑器&#xff0c;emacs 编辑器最开始是作为控制台的编辑器&#xff0c;并且 emacs 编辑器仍然提供最早的命令行模式。 1. 检查 Linux 系统中是否安装 emacs 编辑器 使用如何命令检查 emacs 编…

小主机折腾记22

最近总是心不在焉&#xff0c;于是决定把家里的海景房机箱升级下&#xff0c;顺便把之前剩的x99散热器&#xff0c;蓝宝石RX590&#xff0c;内存硬盘等利用上 咸鱼买了一个长城G6 淘宝买了一张X99D4M4&#xff08;4相8倍供电那款&#xff09; 今天主板到了&#xff0c;开整 先测…

DO-248C:Do-178C和Do-278A的支持信息-常见问题解答 (FAQ) (2)

3.0 常见问题解答 (FAQ) FREQUENTLY ASKED QUESTIONS (FAQ) 本节汇总了 DO-178C 和 DO-278A 常见问题解答。 常见问题解答的目的是对业界经常提出的有关 DO-178C 和/或 DO-278A 材料的问题提供简短而简洁的答复。 这些问题经常向认证机构或提供 DO-178C 和/或 DO-278A 解释的其…

韩国突发:将批准比特币ETF

作者&#xff1a;秦晋 韩国两党宣布将批准比特币ETF。比特币也再次成为竞选的宠儿。 4月10日&#xff0c;韩国将迎来每隔4年而进行的一次立法大选。在大选之前&#xff0c;现执政党与反对党都承诺将批准比特币ETF。 我们知道&#xff0c;比特币的主要受众群体以年轻人居多。此前…

四、分类算法 - 决策树

目录 1、认识决策树 2、决策树分类原理详解 3、信息论基础 3.1 信息 3.2 信息的衡量 - 信息量 - 信息熵 3.3 决策树划分的依据 - 信息增益 3.4 案例 4、决策树API 5、案例&#xff1a;用决策树对鸢尾花进行分类 6、决策树可视化 7、总结 8、案例&#xff1a;泰坦尼…

景联文科技:引领战场数据标注服务,赋能态势感知升级

自21世纪初&#xff0c;信息化战争使战场环境变得更为复杂和难以预测&#xff0c;持续涌入的海量、多样化、多来源和高维度数据&#xff0c;加大了指挥员的认知负担&#xff0c;使其需要具备更强的数据处理能力。 同时&#xff0c;计算机技术和人工智能技术的飞速发展&#xff…

模板的初阶

目录 【本节目标】 1.泛型编程 2.函数模板 2.1函数模板概念 2.1 函数模板格式 2.3函数模板的原理 2.4函数模板的实例化 2.5模板参数的匹配原则 3.类模板 3.1类模板的定义格式 3.2类模板的实例化 【本节目标】 1. 泛型编程 2. 函数模板 3. 类模板 1.泛型编程 如何实现…

jeesite用字典项配置二级下拉选

1、配置字典项 2、html代码&#xff1a;修改下拉选项框 <div class"col-xs-6"><div class"form-group"><label class"control-label col-sm-4" title""><span class"required">*</span> ${…

电脑桌面备忘录怎么设置?如何在电脑桌面上添加便签?

在日常生活中&#xff0c;电脑桌面上的便签功能可以帮助我们更有效地管理待办事项和重要信息。下面就让我们一起来学习电脑桌面备忘录怎么设置&#xff0c;如何在电脑桌面上添加便签吧。 首先&#xff0c;我们需要找到操作系统中的“小部件”或“小工具”选项。通常情况下&…

[C++][linux]Linux上内存共享内存用法

一&#xff0c;什么是共享内存 共享内存&#xff08;Shared Memory&#xff09;&#xff0c;指两个或多个进程共享一个给定的存储区。进程可以将同一段共享内存连接到它们自己的地址空间中&#xff0c;所有进程都可以访问共享内存中的地址&#xff0c;就好像它们是由用C语言函…

【JavaSE】输入输出处理

目录 File类常用方法代码示例 流分类字节流输入流字节流输出流字节流复制粘贴效果字符流输入流字符流输出流Buff版输入输出流二进制流序列化和反序列化 File类 File file new File( String pathname ); 常用方法 代码示例 public static void main(String[] args) {//1.创建…

用友U8 Cloud BlurTypeQuery SQL注入漏洞复现

0x01 产品简介 用友U8 Cloud是用友推出的新一代云ERP,主要聚焦成长型、创新型企业,提供企业级云ERP整体解决方案。 0x02 漏洞概述 用友U8 Cloud BlurTypeQuery接口处存在SQL注入漏洞,未授权的攻击者可通过此漏洞获取数据库权限,从而盗取用户数据,造成用户信息泄露。 …