(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会创建一个栈帧,然后将栈帧压到虚拟机栈中,调用结束时,该方法对应的栈帧会从虚拟机栈中出栈。


相关文章
|
3月前
|
前端开发 Java
java实现队列数据结构代码详解
本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
111 1
|
26天前
|
缓存 NoSQL Java
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
84 6
|
1月前
|
算法 Java 关系型数据库
校招 Java 面试基础题目解析及学习指南含新技术实操要点
本指南聚焦校招Java面试,涵盖Java 8+新特性、多线程与并发、集合与泛型改进及实操项目。内容包括Lambda表达式、Stream API、Optional类、CompletableFuture异步编程、ReentrantLock与Condition、局部变量类型推断(var)、文本块、模块化系统等。通过在线书店系统项目,实践Java核心技术,如书籍管理、用户管理和订单管理,结合Lambda、Stream、CompletableFuture等特性。附带资源链接,助你掌握最新技术,应对面试挑战。
52 2
|
1月前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
118 3
|
1月前
|
安全 Java 编译器
Java 校招面试题目合集及答案 120 道详解
这份资料汇总了120道Java校招面试题目及其详细答案,涵盖Java基础、JVM原理、多线程、数据类型、方法重载与覆盖等多个核心知识点。通过实例代码解析,帮助求职者深入理解Java编程精髓,为校招面试做好充分准备。无论是初学者还是进阶开发者,都能从中受益,提升技术实力和面试成功率。附带的资源链接提供了更多学习材料,助力高效备考。
67 3
|
1月前
|
存储 算法 Java
校招 java 面试基础题目及解析
本文围绕Java校招面试基础题目展开,涵盖平台无关性、面向对象特性(封装、继承、多态)、数据类型、关键字(static、final)、方法相关(重载与覆盖)、流程控制语句、数组与集合、异常处理等核心知识点。通过概念阐述和代码示例,帮助求职者深入理解并掌握Java基础知识,为校招面试做好充分准备。文末还提供了专项练习建议及资源链接,助力提升实战能力。
96 0
|
3月前
|
存储 Java 编译器
Java 中 .length 的使用方法:深入理解 Java 数据结构中的长度获取机制
本文深入解析了 Java 中 `.length` 的使用方法及其在不同数据结构中的应用。对于数组,通过 `.length` 属性获取元素数量;字符串则使用 `.length()` 方法计算字符数;集合类如 `ArrayList` 采用 `.size()` 方法统计元素个数。此外,基本数据类型和包装类不支持长度属性。掌握这些区别,有助于开发者避免常见错误,提升代码质量。
205 1
|
5月前
|
存储 IDE Java
java设置栈内存大小
在Java应用中合理设置栈内存大小是确保程序稳定性和性能的重要措施。通过JVM参数 `-Xss`,可以灵活调整栈内存大小,以适应不同的应用场景。本文介绍了设置栈内存大小的方法、应用场景和注意事项,希望能帮助开发者更好地管理Java应用的内存资源。
255 4
|
7月前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
118 5
|
7月前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
184 5

热门文章

最新文章