目录
一、栈的引出
只能从一端插入元素,也只能从这一端取出元素,我们发现,最先添加的元素就在当前栈的最低端,最后添加的元素就在栈的最顶端。添加元素也只能在栈顶添加。
当取出栈中的元素时,也只能从栈顶开始取出,最后添加的元素最先取出(Last In First Out)。
栈的特点:先进后出,后进先出的线性表,添加元素和删除元素的一端称为栈顶,另外一端称为栈底。
二、栈的实现
基于数组实现的栈-顺序栈
基于链表实现的栈-链式栈
private List<E> data = new LinkedList<>();
package stack;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
/**
* 基于动态数组实现的顺序栈
*/
public class sequentialStack<E> {
//记录当前栈的元素个数
private int size;
//实际存储数据的动态数组,此时在栈中只能在数组末尾添加和删除元素
private List<E> data = new ArrayList<>();
/**
* 向当前栈中添加元素->压栈操作
*
* @param val
*/
public void push(E val) {
//数组的尾部插入
data.add(val);
size++;
}
/**
* 查看当前栈顶元素值
*
* @return
*/
public E peek() {
if (isEmpty()) {
throw new NoSuchElementException("stack is isEmpty!cannot peek!");
}
return data.get(size - 1);
}
/**
* 弹出当前的栈顶元素,返回栈顶元素值
*
* @return
*/
public E pop() {
if (isEmpty()) {
//此时栈为空
throw new NoSuchElementException("stack is isEmpty!cannot pop!");
}
E val = data.get(size - 1);
//删除数组末尾的元素
data.remove(size - 1);
size--;
return val;
}
/***
* 判断当前栈是否为空
* @return
*/
private boolean isEmpty() {
return size == 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < size; i++) {
sb.append(data.get(i));
if (i != size - 1) {
sb.append(", ");
}
}
sb.append("] top");
return sb.toString();
}
}
三、栈的练习题
1、lettcode20
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 == '['){
//此时c是左括号,入栈
stack.push(c);
}else {
//此时碰到了右括号,弹出栈顶元素并且查看是否匹配
//str=>'}])'时
if (stack.isEmpty()){
//肯定是先有左括号,如果第一个字符就是右括号,就一定是false
return false;
}
char top=stack.pop();
//找反例
if (c==')'&& top!='('){
return false;
}
if (c==']'&& top!='['){
return false;
}
if (c=='}'&& top!='{'){
return false;
}
}
}
//当匹配结束后,此时栈不为空,就是左括号数大于右括号数的情况
return stack.isEmpty();
}
2、leetcode125
package stack.Leetcode;
import java.util.Stack;
/**
* 使用两个栈s1和s2,s1是保存元素,s2是保存最小元素
* 当s2为空时,直接入栈,当s2的栈顶元素>当前元素,直接入栈
* 当s2的栈顶元素<当前元素时,就把顶元素在入栈一次(s2的元素个数要和s1的元素个数爆出一致)
* 最后s2的栈顶元素就是最小值
*/
public class Num125 {
//s1保存实际元素
private Stack<Integer> s1=new Stack<>();
//s2栈顶永远是最小值
private Stack<Integer> s2=new Stack<>();
public void push(int val) {
s1.push(val);
if (s2.isEmpty()){
s2.push(val);
}else{
int peek=s2.peek();
s2.push(Math.min(val,peek));
}
}
public void pop() {
s1.pop();
s2.pop();
}
public int top() {
return s1.peek();
}
public int getMin() {
return s2.peek();
}
}