目录
1.栈
1.1栈的概念
特点:先进后出,后进先出的形式组织数据
1.2栈的使用
java自带栈的使用
public static void main(String[] args) {
//实例化一个stack对象
Stack<Integer> stack=new Stack<>();
stack.push(1);//先进来的放栈底
stack.push(2);//依次往上放
stack.push(3);
stack.push(4);//最后一个在栈顶
//pop的返回类型是一个E,这里是Integer,将栈顶元素推出栈
System.out.println(stack.pop());
//peek只是看一眼栈顶函数,而不会将他推出
Integer ret=stack.peek();
System.out.println(ret);
ret=stack.peek();
System.out.println(ret);
//size获取栈中元素个数
System.out.println(stack.size());
}
栈的底层是一个数组
数组实现栈
//需要实现的接口
public interface IStack {
void push(int x);
int pop();
int peek();
int size();
boolean empty();
boolean full();
}
public class EmptyException extends RuntimeException {
public EmptyException(String msg){
super(msg);
}
}
package stackdemo;
import java.util.Arrays;
public class MyStack implements IStack {
private int[] elem;
private int usedSize;
//创建一个默认大小
private static final int DEFAULY_CAPACITY=10;
//创建一个默认大小的数组
public MyStack(){
elem=new int[DEFAULY_CAPACITY];
}
@Override
public void push(int x) {
//满了就进行2倍扩容
if (full()){
//copyof是返回一个数组
elem= Arrays.copyOf(elem,2*elem.length);
}
//usedSize是一个指针指向数组中最后一个元素之后
//及usedSize还可以存放数据下标
elem[usedSize]=x;
usedSize++;
}
@Override
public int pop() {
//先判断是否为空再推出
if (empty()){
throw new EmptyException("栈空了");
}
int old=elem[usedSize-1];//先存下最后一个元素
//相当于是删除,最后一个元素依然在数组里面,只不过指针位置指向了他
//当增加时会把他覆盖,所以数组的删除是覆盖
usedSize--;
//当是引用类型elem[us]=null;
return old;
}
@Override
public int peek() {
//先判断是否为空再推出
if (empty()){
throw new EmptyException("栈空了");
}
int old=elem[usedSize-1];//先存下最后一个元素
//相当于是删除,最后一个元素依然在数组里面,只不过指针位置指向了他
//当增加时会把他覆盖,所以数组的删除是覆盖
//usedSize--;不删就是没得这一步
//当是引用类型elem[us]=null;
return old;
}
@Override
public int size() {
return usedSize;
}
@Override
public boolean empty() {
return usedSize==0;
}
@Override
public boolean full() {//判断数组是否满
if (usedSize==elem.length){
return true;
}
return false;
}
}
链表实现栈
单链表
从尾出或入时,每次都要遍历到最后一个节点,时间复杂度较高
用双链表LinkedList
1.3相关题目
逆波兰表达式求值
代码实现
计算的时候遇到运算符之后运算符前一个在运算符右边,运算符前前一个在运算符左边,然后计算后再存入栈中,代替运算符及其前两个。
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 s){
if (s.equals("+")||s.equals("-")||s.equals("*")||s.equals("/")){
return true;
}else {
return false;
}
}
有效的括号
代码实现
其实就三种情况
1.左括号多
2.右括号多
3.一样多但左右不匹配
思路:左括号入栈,遇到右括号时,比较栈顶元素是否匹配,匹配就pop一下出栈
什么时候匹配?当栈当中元素为空并且字符串也遍历完成了
public boolean isValid(String s) {
Stack<Character> stack=new Stack<>();
//1.遍历字符串
for (int i = 0; i < s.length(); i++) {
char ch=s.charAt(i);
//2.判断是不是左括号
if (ch=='{'||ch=='['||ch=='('){
stack.push(ch);
}else {//此时的ch已经是右括号了
//3.遇到右括号
if (stack.empty()){//如果栈是空的不匹配,这个函数是空的会返回true
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;
}
栈的压出、弹出序列
代码实现
popV是否可能是pushV的出栈序列
思路:
1.遍历push数组,把元素放到栈中
2.每push一个元素,就和pop中数组的元素比较
3.如果相等j++且出栈
4.如果不相等想办法入栈
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 (!stack.empty()&&j<popV.length&&stack.peek()==popV[j]){
stack.pop();//移除相等的数组
j++;
}
}
return stack.empty();//移除完了就等于匹配完了,栈就空了
}
最小栈
代码实现
思路
使用两个栈,一个栈存放元素,一个栈存最小元素,第一个元素都要存,当后面元素比第一个元素小时,存入minStack中,当要返回最小时直接pop()minStack
删除时,当右边元素等于左边栈顶元素时,右边元素也要删除
class MinStack {
private Stack<Integer> stack;
private Stack<Integer> minstack;
private int usedSize;
public MinStack() {
stack = new Stack<>();
minstack = new Stack<>();
}
public void push(int val) {
stack.push(val);
if (minstack.empty()) {
minstack.push(val);
} else {
int peekVal = minstack.peek();
if (val <= peekVal) {//等于的情况也需要
minstack.push(val);
}
}
}
public void pop() {
if (!stack.empty()){
int val=stack.pop();
if (!minstack.empty()){
if (val==minstack.peek()){
minstack.pop();
}
}
}
}
//获取当前普通栈的栈顶元素
public int top() {
return stack.peek();
}
public int getMin() {
if (!minstack.empty()){
return minstack.peek();
}
return -1;
}
}