数据结构中的栈

概念

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

通俗的讲栈其实就是一种数据结构,特点是:先进后出

在这里插入图片描述

此时JVM stack 只是JVM当中的一块内存,该内存一般用来存放
例如:局部变量
调用函数的时候,我们会为这个函数开辟一块内存,叫做栈帧,在哪里开辟那?
JVM stack

什么是栈帧:

就是程序在调用方法的时候,为方法开辟的内存

使用刚刚的概念特点:

看几个题来了解栈到底是怎么实现的。
在这里插入图片描述
我们可以想每个输出序列的第一个元素应该是输入的最后一个,因为栈的特点是先进后出
A选项
在这里插入图片描述
所以出栈序列可以是A选项
B 选项
选项中第一个出现的是d说明一口气入栈到d,先让d出栈,然后在让e入栈在出栈,最后按照顺序出栈就可以
在这里插入图片描述
后面选项都一样,不再一 一列举
在这里插入图片描述

再看看这个题,加深理解

Stack中的方法

方法解释
E push(E item)压栈
E pop()出栈
E peek()查看栈顶元素
boolean empty()判断栈是否为空

拓展

中缀表达式转后缀表达式
在这里插入图片描述
如图就是一个中缀表达式
我们要把它转为后缀表达式,方式:

我们把每个括号里的运算符放到括号外边
后边变为:
在这里插入图片描述
只要将将数字放到栈里,碰到运算符计算,将计算后的数字放进栈里就可以了

后缀表达式又叫逆波兰表达式

逆波兰表达式

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

例题

思路
1.判断是否是运算符
2.如果不是就将字符变为数字放入栈中
3.如果是运算符就将两个数字运算
4.运算后的数字继续放入栈中,
5.重复以上操作直到数组为空

代码如下

import java.util.Stack;

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

例题

题目的大意是输入两个整数序列,第一个序列是栈的压入顺序,第二个是弹出顺序,判断是不是

这题大致思路,就像我们之前在概念中做的题目一样,首先找到出栈序列的第一个,如果后面的相同,就弹出,如果不同的话,将第一个入栈顺序继续加判断是否相同,到最后判断辅助栈是否为空就可以了

import java.util.*;
import java.util.ArrayList;

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

我们使用的栈底层是个数组,那么请问能不能用单链表来实现?
1.先进后出
2.入栈和出栈的时间复杂度都是O(1)
因为链表可以头插也可以尾插,那么入栈使用头插法还是尾插法?
假设:入栈是尾插法那么时间复杂度就是O(n)了,因为尾插法每次都要找尾巴
假设:入栈是头插法,时间复杂度就是O(1),出栈的时候,出栈的时候只需要删除头结点就好了时间复杂度也是O(1)

因为是单链表虽然最后一个节点我知道是那个,但是它的前一个我就不知道了。还要遍历去找这个节点的前驱,时间复杂度又是O(n)了
,使用双链表来实现一个栈,这样完全可以。

还有两个栈的问题:
括号匹配问题
实现一个最小栈

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值