0
点赞
收藏
分享

微信扫一扫

深入理解栈(Stack)

禾木瞎写 2022-07-12 阅读 85

目录

1. 栈(Stack)之概念

2. 栈(Stack)之模拟实现

3. 栈(Stack)之使用

4.栈(Stack)之使用场景

4.1 改变元素的序列

4.2 将递归转化为循环

4.3 括号匹配

4.4 逆波兰表达式求值

4.5 出栈入栈次序匹配


1. 栈(Stack)之概念

首先明确:

 下面理解一下,先进后出,看图解

分析一下,

1. 栈是先进后出的,那么入栈和出栈的时间复杂度是多少

2. 前面说的顺序存储的方式,那么栈的链式存储是什么样的

3. 如果是以双向链表来看做栈,那么从哪里入哪里出 


2. 栈(Stack)之模拟实现

先写一个栈

public int[] elem;
    public int usedSize;

    public static final int DEFAULT_CAPATI = 10;

    public MyStack() {
        elem = new int[DEFAULT_CAPATI];
    }

  1.入栈push()

入栈前先要判断栈是否满的isFull()

    public boolean isFull() {
        if (usedSize == elem.length) {
            return true;
        }
    return false;
    }
    public void push(int val) {
        //判断栈满
        if (isFull()) {
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        usedSize++;
    }

2.删除栈顶元素pos()

删除栈顶元素前,先判断栈空isEmpty()

    public boolean isEmpty() {
        return usedSize == 0;
    }

如果栈是空的,还要写一个异常EmptyStackException

public class EmptyStackException extends RuntimeException{
    public EmptyStackException() {

    }
    public EmptyStackException(String msg) {
        super(msg);
    }
}
    public int pop() {
        if (isEmpty()) {
            throw new EmptyStackException("栈是空的");
        }
        int oldVal = elem[usedSize-1];
        usedSize--;
        return oldVal;
    }

 3.获取栈顶元素,不删除peek()

    public int peek() {
        if (isEmpty()) {
            throw new EmptyStackException("栈是空的");
        }
        return elem[usedSize-1];
    }

4.获取中有效元素个数getUsedSize()

    public int getUsedSize() {
        return usedSize;
    }

3. 栈(Stack)之使用

    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(7);
        System.out.println(stack.size());
        System.out.println(stack.peek());
        stack.pop();
        System.out.println(stack.pop());
    }

 

4.栈(Stack)之使用场景

4.1 改变元素的序列

(1)先看牛客上的一道题

 

 分析一下 ,答案选C

 分析一下,答案选C

 

分析一下,答案选B

 


 

4.2 将递归转化为循环

写一个逆序打印链表

(1)递归

public class Demo01 {
    static class Node{
        public int val;
        public Node next;
        public Node(int val) {
            this.val = val;
        }
    }
    public Node head;
    public void printList(Node head) {
        if (head == null) {
            return;
        }
        if (head.next == null) {
            System.out.print(head.val + " ");
            return;
        }
        printList(head.next);
        System.out.print(head.val + " ");
    }
}

(2)非递归实现

既然栈是先进后出的,那么可以将数字依次放进去,然后再pop取出栈顶元素,打印出来,这不就实现了逆序打印

    public void printList2(Node head) {
        Stack<Node> stack = new Stack<>();
        Node cur = head;
        //将元素全部依次放入栈中
        while(cur != null) {
            stack.push(cur);
            cur = cur.next;
        }
        //给栈pop取出栈顶元素然后拿出val打印
        while(!stack.empty()) {
            Node top = stack.pop();
            System.out.println(top.val + " ");
        }
    }

4.3 括号匹配

链接   20. 有效的括号 - 力扣(LeetCode)

题目要求

分析一下

 上代码

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 {
                //此时ch 是右括号
                //说明走到右边括号了
                if(stack.empty()) {
                    //遇到有括号了,但是栈空了,说明1.右括号多
                    return false;
                }
                char top = stack.peek();
                if(ch == ')' && top == '(' || ch == ']' && top == '[' || ch == '}' && top == '{') {
                    //说明当前字符是匹配的
                    stack.pop();
                }else {
                    //2.左右括号不匹配
                    return false;
                }
            }
        }
        if(stack.empty()) {
            return true;
        }else {
            //3.说明是左括号多
            return false;
        }
    }
}

 

4.4 逆波兰表达式求值

链接 150. 逆波兰表达式求值 - 力扣(LeetCode)

在说这道题前先明白 逆波兰表达式又叫做后缀表达式

(1)后缀表达式又可以通过中缀表达式来转化出来(考研-选择题)

 所以中缀变后缀三步走

(2)后缀表达式计算结果(代码题)

后缀计算4步走

 好了,下面看一下这道题

根据前面的后缀计算4步走验证一下这个例子

 

class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        for(String x : tokens) {
            if(!isOperation(x)) {
                //不是加减乘除
                //字符转成整数.放进栈中
                stack.push(Integer.parseInt(x));
            }else {
                int num2 = stack.pop();
                int num1 = stack.pop();
                switch(x) {
                    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 isOperation(String opera) {
        if(opera.equals("+") || opera.equals("-") || opera.equals("*") || opera.equals("/")) {
            return true;
        }
        return false;
    }
}

 


4.5 出栈入栈次序匹配

链接 栈的压入、弹出序列_牛客题霸_牛客网 (nowcoder.com)

题目要求:

分析一下

 上代码 

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

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

举报

相关推荐

0 条评论