(Java)数据结构之栈(Stack) ,附有三个栈相关OJ题目和对应做法(括号匹配,逆波兰表达式求值,出栈入栈次序匹配)

简介: 栈是一种特殊的线性表,它只能在固定的一端进行插入和删除操作,进行数据插入和删除的一端为栈顶,另一端为栈底。栈中的元素遵循后进先出(LIFO)(Last In First Out)的原则。

1. 栈的概念

栈是一种特殊的线性表,它只能在固定的一端进行插入和删除操作,进行数据插入和删除的一端为栈顶,另一端为栈底。栈中的元素遵循后进先出(LIFO)(Last In First Out)的原则。


压栈:栈的插入数据操作叫做进栈,压栈,入栈。入数据在栈顶


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

image.png



2. 栈的使用

方法 功能说明


Stack() 构造一个空栈


E push(E e) 将e入栈并返回e


E pop() 将栈顶元素出栈并返回


E peek() 获取栈顶元素


int size() 获取栈中有效元素的个数


boolean empty() 检测栈是否为空



将上述方法进行代码展示:

public class TestStack {
    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());
        s.pop();
        System.out.println(s.peek());
        if(s.empty()){
            System.out.println("栈空");
        }else{
            System.out.println("栈不空,元素个数为:"+s.size());
        }
    }
//结果:
      4
      3
      栈不空,元素个数为:3


使用栈将递归转化为循环:

// 递归方式
    void printList(Node node){
        if(null != node){
            printList(node.next);
            System.out.print(node.val + " ");
        }
    }
    // 循环方式
    void printList(Node node){
        if(null == node){
            return;
        }
        Stack<Node> s = new Stack<>();
// 将链表中的结点保存在栈中
        Node cur = node;
        while(null != cur){
            s.push(cur);
            cur = cur.next;
        }
// 将栈中的元素出栈
        while(!s.empty()){
            System.out.print(s.pop().val + " ");
        }
    }


3. 栈的OJ题

1. 括号匹配(LeetCode20)有效的括号


可以进入上面链接查看题目


方法:


1. 依次拿到字符串的元素,如果该元素是左括号,则入栈


2. 如果不是左括号,先判断栈是否为空,如果为空则返回false,如果不为空则进行后续操作


3. 拿到栈顶的元素与前面所拿到字符串的元素作比较,如果括号匹配,则栈顶元素出栈,结束当前循环,继续进行后续比较,如果括号不匹配,则返回false


4. 当字符串的元素比较完后,判断栈是否有剩余,如果有剩余,则返回false,无剩余则返回true


参考代码:

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i=0;i<s.length();i++){
            char c = s.charAt(i);
            if(c=='('||c=='{'||c=='['){
                stack.push(c);
            }else{
                if(stack.empty()){
                    return false;
                }
                char top = stack.pop();
                if(top=='{'&&c=='}'||top=='['&&c==']'||top=='('&&c==')'){
                    continue;
                }else{
                    return false;
                }
            }
        }
        if(!stack.empty()){
            return false;
        }
        return true;
    }
}



2.逆波兰表达式求值(LeetCode150)逆波兰表达式求值


可以进入上面链接查看题目


方法:


1. 依次将字符串入栈,如果字符串不是算数符号,则入栈


2. 当字符串是算数符号的时候,取栈顶的两个元素进行算数运算


3. 将运算的结果继续入栈


4. 依次进行上述循环


5. 最后返回栈顶元素的值,即所求逆波兰表达式的值


参考代码:

class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> s = new Stack<>();
        for(String e : tokens){
            if(!(e.equals("+")||e.equals("-")||e.equals("*")||e.equals("/"))){
                s.push(Integer.parseInt(e));//将字符e转为整型
            }else{
                int right = s.pop();
                int left = s.pop();
                switch(e) {
                    case "+":
                    s.push(left+right);
                    break;
                    case "-":
                    s.push(left-right);
                    break;
                    case "*":
                    s.push(left*right);
                    break;
                    case "/":
                    s.push(left/right);
                    break;
                }
            }
        } 
        return s.peek();  
    }
}


3. 出栈入栈次序匹配(JZ31)栈的压入、弹出序列


方法:


1. 当入栈序列的元素小于出栈序列的第一个元素,将入栈序列的元素依次入栈


2. 每入栈一个元素,入栈序列的下标加1


3. 当入栈序列的元素与出栈序列的元素相等时,进行出栈,并且出栈序列下标加1


4. 当出栈序列的元素遍历完后,返回true


参考代码:

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Stack<Integer> s = new Stack<>();
        int inIndex = 0;
        int outIndex = 0;
        while(outIndex<popped.length){
            while(s.empty()||s.peek()!=popped[outIndex]){
                if(inIndex<pushed.length){
                    s.push(pushed[inIndex]);
                    inIndex++;
                }
                else{
                    return false;
                }
            }
            s.pop();
            outIndex++;
        }
        return true;    
    }
}


4. 栈的模拟实现

public class MyStack<E> {
    E[] array;
    int size;
    public MyStack(){
        array = (E[])new Object[3];
    }
    public E push(E e){
        ensureCapacity();
        array[size++] = e;
        return e;
    }
    public E pop(){
        E e = peek();
        size--;
        return e;
    }
    public E 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);
        }
    }
}


5. 栈,虚拟机栈,栈帧的区别

栈:一种后进先出的数据结构,继承自Vector


虚拟机栈:具有特殊作用的一块内存空间。栈区:是线程私有的,存放的是函数调用相关信息,主要是栈帧,它是按照数据结构中栈的特性来实现的


栈帧:一种结构,与函数调用相关。内部:局部变量表,操作数栈。每个方法运行时JVM会创建一个栈帧,然后将栈帧压到虚拟机栈中,调用结束时,该方法对应的栈帧会从虚拟机栈中出栈。


相关文章
|
1月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
69 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
3月前
|
存储 算法 Java
惊!Java程序员必看:JVM调优揭秘,堆溢出、栈溢出如何巧妙化解?
【8月更文挑战第29天】在Java领域,JVM是代码运行的基础,但需适当调优以发挥最佳性能。本文探讨了JVM中常见的堆溢出和栈溢出问题及其解决方法。堆溢出发生在堆空间不足时,可通过增加堆空间、优化代码及释放对象解决;栈溢出则因递归调用过深或线程过多引起,调整栈大小、优化算法和使用线程池可有效应对。通过合理配置和调优JVM,可确保Java应用稳定高效运行。
140 4
|
21天前
|
存储 算法 Java
🧠Java零基础 - Java栈(Stack)详解
【10月更文挑战第17天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
16 2
|
1月前
|
存储 Java
数据结构第三篇【链表的相关知识点一及在线OJ习题】
数据结构第三篇【链表的相关知识点一及在线OJ习题】
26 7
|
1月前
|
存储 Java
数据结构第二篇【关于java线性表(顺序表)的基本操作】
数据结构第二篇【关于java线性表(顺序表)的基本操作】
30 6
|
1月前
|
存储 安全 Java
【用Java学习数据结构系列】探索栈和队列的无尽秘密
【用Java学习数据结构系列】探索栈和队列的无尽秘密
30 2
|
2月前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
384 8
|
1月前
|
算法 Java 测试技术
数据结构 —— Java自定义代码实现顺序表,包含测试用例以及ArrayList的使用以及相关算法题
文章详细介绍了如何用Java自定义实现一个顺序表类,包括插入、删除、获取数据元素、求数据个数等功能,并对顺序表进行了测试,最后还提及了Java中自带的顺序表实现类ArrayList。
19 0
|
3月前
|
Java 索引
java中的栈(利用数组实现栈)
这篇文章通过Java代码示例介绍了如何使用数组实现栈操作,包括栈的初始化、入栈、出栈、判断栈满和空以及遍历栈的方法。
java中的栈(利用数组实现栈)
|
3月前
|
数据采集 供应链 JavaScript
分享基于Java开发的Java毕业设计实战项目题目
这篇文章分享了67套基于Java开发的毕业设计实战项目题目,覆盖了互联网、企业管理、电子政务、Java基础项目、ERP系统、校园相关、医疗以及其他细分行业等多个领域,并推荐了使用IDEA、Vue和Springboot的技术栈。