文章目录
栈的概念
- 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出的原则。
- 入栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
- 出栈:栈的删除操作叫做出栈。出数据在栈顶
栈的使用
栈中的方法
栈的使用示例
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()); // 获取栈中有效元素个数---> 4
System.out.println(s.peek()); // 获取栈顶元素---> 4
s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
if(s.empty()){
System.out.println("栈空");
}else{
System.out.println(s.size());
}
}
栈的模拟实现
//使用数组实现栈
import java.util.ArrayList;
import java.util.Arrays;
public class MyStack {
public int[] elem;
public int usedSize;
public MyStack() {
elem = new int[10];//初始化容量为10
}
public void push(int val) {
if(isFull()) {
elem = Arrays.copyOf(elem,2*elem.length);
}
elem[usedSize] = val;
usedSize++;
}
private boolean isFull() {
return usedSize == elem.length;
}
public void pop() {
if(isEmpty()) {
return;
}
int oldValue = elem[usedSize-1];
usedSize--;
System.out.println(oldValue);
}
private boolean isEmpty() {
if(usedSize == 0) {
return true;
}
return false;
}
public void peek() {
if(usedSize == 0) {
return;
}
System.out.println(elem[usedSize-1]);
}
}
栈相关面试题
括号匹配 --------OJ链接
遍历字符串S,将字符串S,按照下标 i 依次转换为字符 赋值给 ch ,先判断入栈的字符是否为左括号,如果是左括号直接入栈,如果不是左括号,要判断此时栈是否为空,如果为空,则返回 false ;如果不为空,判断栈顶元素 topL 是否和 ch 相互匹配,如果匹配, pop 出栈顶元素,如果不匹配return false。最后判断栈是否为空,为空的话说明括号全部匹配,元素全部出栈,如果栈不为空,则说明有 括号没有匹配到 。(此时的括号为左括号)
【步骤】
遍历字符串
判断是左括号 还是 右括号,左括号直接入栈,不是左括号判断此时栈是否为空,为空return false;
不为空,判断与栈顶元素是否匹配,匹配弹出栈顶元素;不匹配 return false;
字符串遍历完成,栈不为空(此时栈中一定是左括号),return false;为空 return true。
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for(int i = 0; i < s.length(); i++) {
Character ch = s.charAt(i);
if(ch == '(' || ch == '{' || ch == '[') {
stack.push(ch);
}else {
if(stack.empty()) {
return false;
}
Character topL = stack.peek();
if(topL == '(' && ch == ')' || topL == '{' && ch == '}' || topL == '[' && ch == ']') {
stack.pop();
}else return false;
}
}
if(!stack.empty()) {
return false;
}
return true;
}
逆波兰表达式求值--------OJ链接
假设逆波兰表达式为:1+23+(45)+6,它的逆波兰表达式为:1 2 3 * + 4 5 * 6 + 7 * +
【解题思路】将逆波兰表达式按照从左往右的方向遍历,遇到数字就入栈,
遇到运算符号,取出栈中的两个元素,第一个元素放在 运算符的右边,第二个元素放在 运算符的左边,然后把运算结果再次放入栈中。
遍历完逆波兰表达式的字符串后,栈中的元素就是最终的运算结果
出栈入栈次序匹配--------OJ链接
遍历数组,先让 pushV[i] 数组元素入栈,入栈后判断栈顶元素 是否等于 popV[j] ,如果相等,出栈顶元素,j ++;这里的判断及操作,需要while()循环进行,因为可能栈顶元素 和 popV[j] 的值仍然相等,循环条件不能仅仅是 stack.peek() == popV[j]
,还要要求此时栈不为空,且 j 下标不越界【因为 有 pop() 操作,和 j++ 操作,有可能出现栈为空,或者 数组下标 j 越界】
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 < pushV.length && !stack.empty() && stack.peek() == popV[j]) {
stack.pop();
j++;
}
}
return stack.empty();
}
最小栈-------OJ链接
另外创建一个栈 minStack ,用来存放此时正常栈中的最小元素
minStack栈中 记录每次入正常栈时,该栈中的最小元素值。因此minStack的栈顶元素就是此时该正常栈中最小的元素
当向正常栈中 放入元素时,如果此时 minStack 栈中为空,则把该元素压入minStack栈中。此后minStack栈中不为空,当再次向正常栈中放入元素时,判断该元素 是否小于等于 minStack 中的栈顶元素 ,如果小于等于,把该元素放入 minStack 栈中,否则不入栈【注意条件是 “<=”,如果正常栈中存在两个相等的最小值,那么当把其中一个最小值pop之后,此时栈中最小值还是相同的】
当正常栈 pop() 栈顶元素时,判断pop() 出的元素 是否 等于 minStack 中的栈顶元素,如果等于,把minStack中的栈顶元素也 pop() 出去,因为此时该栈中的最小元素已经pop,对应minStack也该把该栈栈顶元素pop,此时minStack的栈顶元素,还是正常栈中的最小元素
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 {
int topVal = minStack.peek();
if(val <= topVal) {
minStack.push(val);
}
}
}
public void pop() {
int topVal = stack.peek();
if(topVal == minStack.peek()) {
minStack.pop();
}
stack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}