当前位置: 首页 > article >正文

数据结构-Stack和栈

1.栈

1.1什么是栈

栈是一种特殊的线性表,只允许在固定的一段进行插入和删除操作,进行插入和删除操作的一段称为栈顶,另一端称为栈底。

栈中的数据元素遵顼后进先出LIFO(Last In First Out)的原则,就像一叠盘子,只能在顶部添加或移除盘子。

压栈:栈的插入操作叫做压栈/进栈/入栈,新插入的元素在栈顶。

出战:栈的删除操作叫做出栈,要删除的 元素在栈顶。

从图上观察发现:无论是插入还是删除操作,栈底的位置不发生变化,但是栈顶的位置会随插入或删除操作而发生变化。

1.2栈的常用方法

在Java标准库中提供了java.util.Stack(栈的实现类),此处的常用方法指的是Stack的常用方法。

Stack的常用方法如下表所示:

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

注意:

pop()是删除元素,并返回删除(删除前的栈顶元素)的元素

peek()是获取栈顶元素并返回,不进行出栈操作

常用方法的代码演示:

public class Test {
    public static void main(String[] args) {
        Stack<String> stack=new Stack<>();
        //入栈
        stack.push("My");
        stack.push("name");
        stack.push("is");
        stack.push("hajimi");
        //获取栈中有效元素的个数-->4
        System.out.println(stack.size());
        //获取栈顶元素-->hajimi  遵循后进先出
        System.out.println(stack.peek());
        //peek方法不会改变栈中的元素个数
        System.out.println(stack.size());
        //出栈
        String deleteElem=stack.pop();
        //获取栈中有效元素的个数-->3
        System.out.println(stack.size());
        //判断栈是否为空-->false
        System.out.println(stack.isEmpty());
    }
}

2.Stack

2.1什么是Stack 

Java提供了多种方式来实现栈,包括使用java.util.Stack类,使用Deque接口,或者手动实现栈。

java.util.Stack是Java标准库中提供的一个栈实现类。它继承自Vector类,是一个线程安全的栈实现。


 2.2 Stack的特点

1.线程安全:

由于Stack继承自Vector,它的所有方法都是同步的(线程安全的)。

2.动态扩容:

Stack的底层是Vector,它会根据需要进行动态扩容。

这是Vector的动态扩容方法的原码:

2.3 Stack的局限性

虽然Stack提供了很方便的栈操作,但仍存在一些局限性:

1.继承自Vector:Stack继承自Vector,意味着它继承了一些与栈无关的方法,可能会导致误用

2.性能问题:由于Stack是线程安全的,它的同步机制可能会导致性能的下降,尤其是单线程环境中

2.4实现一个Stack

Stack的底层是Vector,而Vector的底层是数组,接下来我们来编写自己的"Stack"。

代码编写:

package datastructure;

import java.util.Arrays;

public class MyStack2 {
    //用来存放栈中的元素
    private int[] elem;
    //计算栈中有效元素的个数
    private int usedSize;
    //默认初始容量
    private static final int DEFAULT_SIZE=10;
    public MyStack2(){
        this.elem=new int[DEFAULT_SIZE];
    }
    //判断栈是否已满
    private boolean isFull(){
        return elem.length==usedSize;
    }
    //判断栈是否为空
    private boolean isEmpty(){
        return usedSize==0;
    }
    //元素入栈方法
    public void push(int val){
        //判断栈是否已满,如果已满进行扩容
        if(isFull()){
            Arrays.copyOf(elem,2*elem.length);
        }
        //将元素压入,并将有效元素的个数加一
        elem[usedSize++]=val;
    }
    //元素出栈操作
    public int pop(){
        if(isEmpty()){
            System.out.println("栈中没有元素,无法进行出栈操作");
            return Integer.MAX_VALUE;
        }
        //获取栈顶元素,即要删除的元素
        int deleteElem=elem[usedSize-1];
        usedSize--;
        return deleteElem;
    }
    //获取栈顶元素
    public int peek(){
        if(isEmpty()){
            System.out.println("栈为空,无法获取栈顶元素");
            return Integer.MAX_VALUE;
        }
        return elem[usedSize-1];
    }
    //计算栈中元素的个数
    public int size(){
        return usedSize;
    }
}

对上述的代码进行运行测试:

public class Test {
    public static void main(String[] args) {
        MyStack2 myStack2=new MyStack2();
        myStack2.push(1);
        myStack2.push(2);
        myStack2.push(3);
        myStack2.push(4);
        myStack2.push(5);
        System.out.println("当前栈中元素的个数:"+myStack2.size());
        System.out.println("获取栈顶元素:"+myStack2.peek());
        System.out.println("进行出栈:"+myStack2.pop());
        System.out.println("当前栈中元素的个数:"+myStack2.size());
        System.out.println("获取栈顶元素:"+myStack2.peek());
    }
}

运行结果:

3.栈,虚拟机栈,栈帧

概念区分:栈,虚拟机栈和栈帧  

栈:一种数据结构,遵循后进先出(LIFO)的原则,允许在栈顶进行元素的插入和删除操作,常用于括号匹配,表达式求值,深度优先搜索等场景。

虚拟机栈:Java虚拟机(JVM)运行时数据区的一部分,用于存储方法调用,局部变量。每个线程都具有一个自己的虚拟机栈,虚拟机栈中存储的是栈帧

栈帧:是虚拟机栈中的一个条目,用于存储方法调用的相关信息。每个方法调用都会创建一个栈帧,并将其压入虚拟机栈,方法结束后,栈帧会被弹出。

4.栈的应用-逆波兰表达式求值

4.1 什么是逆波兰表达式

逆波兰表达式,也称后缀表达式,是一种特殊的算数表达式表示方式。在逆波兰表达式中,操作符位于操作数之后,这种表达方式的优点式不需要括号来表示操作的优先级,从而简化了表达式的解析和计算

4.2 逆波兰表达式的特点

1.操作符在操作数之后:例如,普通的表达式 (中缀表达式)5 - 2 在逆波兰表达式中表示为 5 2 -

2.无需括号:由于操作符位置明确,不需要括号来表示优先级

3.易于计算:可以使用栈这种数据结构计算表达式的值

4.3 如何用栈解决逆波兰表达式求值

我们知道栈遵循后入先出(Last In First Out)的原则,逆波兰表达式中操作符位于操作数之后,我们可以根据这两个特点对元素进行出栈和入栈操作。

1.先初始化一个空栈

2.从左向右扫描表达式,如果遇到操作数就将其压入栈中,如果遇到操作符,就从栈中弹出两个元素,进行计算,并将计算的结果压入栈中

3.表达式扫描完成后,栈顶元素即为计算的结果

假设传递的参数是一个数组:tokens=["2","1","+","3","*"]

将其转为中缀表达式:(2+1)*3=9

代码编写:

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


http://www.kler.cn/a/527390.html

相关文章:

  • Day52:range()函数
  • Android13源码下载和编译过程详解
  • Ubuntu 18.04安装Emacs 26.2问题解决
  • 14-8C++STL的queue容器
  • 供应链系统设计-供应链中台系统设计(十二)- 清结算中心设计篇(一)
  • 【Rust自学】15.1. 使用Box<T>智能指针来指向堆内存上的数据
  • python学opencv|读取图像(五十二)使用cv.matchTemplate()函数实现最佳图像匹配
  • FBX SDK的使用:基础知识
  • mysql索引snkw
  • 数组排序算法
  • 感悟人生路
  • Springboot项目开发的通用集成
  • 白话DeepSeek-R1论文(一)|AI的顿悟时刻:DeepSeek-R1-Zero 纯强化学习解锁推理新境界
  • AnyThingLLM本地私有知识库搭建
  • HIVE介绍(五)_hive limit
  • 为AI聊天工具添加一个知识系统 之81 详细设计之22 符号逻辑 之2
  • (笔记+作业)书生大模型实战营春节卷王班---L0G2000 Python 基础知识
  • 青少年编程与数学 02-008 Pyhon语言编程基础 09课题、布尔与判断语句
  • DeepSeek能执行程序吗?
  • 基于Spring Security 6的OAuth2 系列之八 - 授权服务器--Spring Authrization Server的基本原理
  • C++并行化编程
  • 解析 Oracle 中的 ALL_SYNONYMS 和 ALL_VIEWS 视图:查找同义词与视图的基础操作
  • 计算机网络一点事(21)
  • 主流的AEB标准有哪些?
  • UE5 GAS RPG Character Classes
  • 翻译: Dario Amodei 关于DeepSeek与出口管制二