目录
1. 概念
2. 栈的使用
2.1 方法
2.2 示例
3. 栈的模拟实现
4. 栈的应用场景
4.1 题目1:不可能的出栈序列
4.2 题目2:逆序打印单链表
4.3 题目3:逆波兰表达式求值
4.4 题目4:括号匹配
4.5 题目5:栈的压入、弹出训练
4.6 题目6:最小栈
1. 概念
(1)栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。
(2)进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。
(3)栈中的数据元素遵循后进先出的原则;
(4)压栈:栈的插入操作叫做进栈或压栈或入栈,入数据在栈顶;
出栈:栈的删除操作叫做出栈,出数据在栈顶;
2. 栈的使用
2.1 方法
方法 | 功能 |
Stack() | 构造一个空栈 |
E push(E e) | 将e入栈并返回e |
E pop() | 将栈顶元素出栈并返回 |
E peek() | 获取栈顶元素 |
int size() | 获取栈中有效元素个数 |
boolean empty() | 检测栈是否为空 |
2.2 示例
public static void main(String[] args) {Stack<Integer> stack = new Stack<>();for(int i=0;i<=5;i++){stack.push(i); // 压栈}// 获取栈顶元素System.out.println(stack.peek());Integer a = stack.pop(); // 出栈栈顶元素System.out.println(a);System.out.println(stack.peek());System.out.println(stack.size());}
3. 栈的模拟实现
Stack继承于Vector,查Vector源码可知vector内部用数组实现,故而模拟实现采用数组栈;
(1)包类关系:
(2)MyStack:
package TestMyStack;import java.util.Arrays;public class MyStack {public int[] elem;public int useSize;public MyStack(){this.elem = new int[10];}// 压栈public void push(int val){if(isFull()){// 扩容reSize();}elem[useSize] = val;this.useSize++;}// 判满public boolean isFull(){if(elem.length == this.useSize){return true;}return false;}// 扩容public void reSize(){elem = Arrays.copyOf(elem, 2*elem.length);}// 出栈并返回出栈元素public int pop(){if(isEmpty()){throw new EmptyException();}
// int val = elem[this.useSize-1];
// this.useSize--;
// return val;return this.elem[--this.useSize];}// 判空public boolean isEmpty(){return this.useSize==0;}// 获取栈顶元素public int peek(){return this.elem[this.useSize-1];}
}
(3)EmptyException:
package TestMyStack;public class EmptyException extends RuntimeException{public EmptyException(){}
}
4. 栈的应用场景
4.1 题目1:不可能的出栈序列
若进栈序列为1,2,3,4,进栈过程中可以出栈,则不可能的出栈序列是:C
A. 1,4,3,2 B. 2,3,4,1 C.3,1,4,2 D.3,4,2,1
4.2 题目2:逆序打印单链表
(1)单链表的递归逆序打印法:
public void fun1(ListNode pHead){// 递归逆序打印单链表if(pHead == null){return;}if(pHead.next == null){System.out.println(pHead.val);}fun1(pHead.next);System.out.println(pHead.val);}
(2)单链表的循环递归逆序打印法:
public void fun2(ListNode pHead){Stack<ListNode> stack = new Stack<>();ListNode cur = head;while(cur!=null){stack.push(cur);cur = cur.next;}// 遍历栈while(!stack.isEmpty()){ListNode top = stack.pop();System.out.print(top.val+" ");}System.out.println();}
4.3 题目3:逆波兰表达式求值
题目链接:150. 逆波兰表达式求值 - 力扣(LeetCode)
解题思路:遍历后缀算数表达式数组,若为数据则入栈,若为算术运算符则出栈栈顶两元素分别作为后操作数和前操作数,再将计算结果入栈,继续向后遍历数组,循环操作,直至栈中仅有一个元素,就是最终值;
代码:
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 x){if(x.equals("+")||x.equals("-")||x.equals("*")||x.equals("/")){return true;}return false;}
}
4.4 题目4:括号匹配
题目链接: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{// 第一种情况:第一个就是右括号,没有元素入栈,栈为空,直接返回假if(stack.empty()){return false; }// 第二种情况:栈不为空,判断是否匹配char ch2 = stack.peek(); //栈顶元素,必为左括号if(ch2 == '('&& ch == ')' || ch2 == '{' && ch == '}' || ch2 == '[' && ch == ']'){stack.pop();}else{return false;}}}if(!stack.empty()){return false;}return true;}
}
4.5 题目5:栈的压入、弹出训练
题目链接:栈的压入、弹出序列_牛客题霸_牛客网
解题思路:定义i下标遍历pushV,j下标遍历popV,将pushV的元素入栈,当二者元素不相等时,继续入栈pushV元素;当二者元素相等时,出栈栈顶元素,i和j均++;
代码:
import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param pushV int整型一维数组 * @param popV int整型一维数组 * @return bool布尔型*/public boolean IsPopOrder (int[] pushV, int[] popV) {Stack<Integer> stack = new Stack<>();int j=0;for(int i=0;i<pushV.length;i++){stack.push(pushV[i]);while(j<popV.length && !stack.empty() && stack.peek().equals(popV[j])){stack.pop();j++;}}return stack.empty();}
}
4.6 题目6:最小栈
题目链接:155. 最小栈 - 力扣(LeetCode)
解题思路:为目标栈开辟一个储存最小值的栈,依次遍历目标栈,将最小的元素入栈最小栈,最小栈栈顶元素就是目标栈的最小元素,且能在常数时间内检索到最小元素;
代码:
class MinStack {private Stack<Integer> stack;private Stack<Integer> minStack;public MinStack() {stack = new Stack<>();minStack = new Stack<>();}public void push(int val) {stack.push(val);if(minStack.empty()){minStack.push(val);}else{ //minStack不为空if(val <= minStack.peek()){ // 如果要插入的值比minStack的栈顶元素小minStack.push(val); // 注意当val==minStack栈顶元素时,也需要将该元素入栈minStack// 因为stack出栈元素时,如果该元素是minStack中的元素,该元素也需要出栈// 以保证在出栈stack最小元素时,minStack中的最小元素不受影响}}}public void pop() {if(!stack.empty()){Integer val = stack.pop();if(val.equals(minStack.peek())){minStack.pop();}// 如果对元素拆箱为int类型,就可使用==进行判等}}public int top() {if(!stack.empty()){return stack.peek();}return -1;}public int getMin() {return minStack.peek();}
}