一、栈的简介
栈(Stack)是一种常用的数据结构,其核心特点是先进后出。栈主要提供三种基本操作:push(入栈,将元素放入栈顶)、pop(出栈,取出并删除栈顶元素)、peek/top(查看栈顶元素但不删除)。栈可以用数组或链表实现,数组实现操作简单、随机访问快,但容量固定或需要扩容;链表实现则不受容量限制,但需要额外的指针空间。最小栈(MinStack)还可以在 O(1) 时间内获取当前栈的最小值,通过额外的辅助栈记录历史最小值实现。
二、IStack
public interface IStack {
void push(int x);
int pop();
int size();
boolean empty();
boolean full();
}
这段代码定义了一个栈的接口 IStack,用于规范栈的基本功能。接口中声明了五个方法:
push(int x):将元素 x 入栈。
pop():从栈顶弹出元素并返回,如果栈为空,通常会抛出异常。
size():返回栈中当前元素的个数。
empty():判断栈是否为空。
full():判断栈是否已满。
三、MyStack
import java.util.Arrays;
public class MyStack implements IStack{
private int[] elem;
private int usedSize;
private static final int DEFAULT_CAPACITY=10;
public MyStack(){
elem=new int[DEFAULT_CAPACITY];
}
@Override
public void push(int x) {
if(full()){
elem=Arrays.copyOf(elem,2*elem.length);
}
elem[usedSize++]=x;
}
@Override
public int pop() {
if(empty()){
throw new EmptyException("栈空了");
}
int old=elem[usedSize-1];
usedSize--;
return old;
}
public int peek(){
if(empty()){
throw new EmptyException("栈空了");
}
return elem[usedSize-1];
}
@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;
}
}
这段代码实现了一个顺序栈(数组栈),它通过数组 elem 存储栈中的元素,并用 usedSize 记录当前栈中元素的个数。栈的容量初始为 DEFAULT_CAPACITY(10),当数组满时,push 方法会通过 Arrays.copyOf 将数组扩容为原来的两倍,以保证栈可以动态增长。
push(int x) 将元素放入栈顶并更新 usedSize;
pop() 从栈顶弹出元素并返回,同时判断栈是否为空,若为空则抛出自定义异常 EmptyException;
peek() 查看栈顶元素但不删除,也会在空栈时抛异常。
size() 返回栈中当前元素数量,empty() 判断栈是否为空,full() 判断栈是否已满。
四、MinStack
import java.util.Stack;
public 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 peekVal=minStack.peek();
if(val<peekVal){
minStack.push(val);
}
}
}
public void pop(){
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;
}
}
import java.util.Stack;
public 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 peekVal=minStack.peek();
if(val<peekVal){
minStack.push(val);
}
}
}
public void pop(){
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;
}
}
这段代码实现了一个最小栈,它可以在 O(1) 时间内获取当前栈中的最小值。代码使用了两个 Stack<Integer> 对象:stack 用于存储所有入栈的元素,而 minStack 用于记录栈中历史最小值。
当执行 push 操作时,如果 minStack 为空或新元素比当前最小值小,就将新元素压入 minStack;这样 minStack 的栈顶始终是当前最小值。
pop 操作会先从 stack 弹出元素,如果弹出的值等于 minStack 栈顶,也同步弹出 minStack 的栈顶,以保证最小值的正确性。
top() 方法返回当前栈顶元素,而 getMin() 返回当前最小值。
五、EmptyException
public class EmptyException extends RuntimeException{
public EmptyException(String msg){
super(msg);
}
}
这段代码定义了一个自定义异常类 EmptyException,它继承自 Java 的 RuntimeException,用于在程序运行时表示"栈或队列为空"的特殊情况。构造方法 EmptyException(String msg) 接收一个字符串参数 msg,并调用父类 RuntimeException 的构造方法,将提示信息传递给异常对象。当栈或队列等数据结构在执行 pop、peek 等操作时,如果当前没有元素,就可以抛出这个异常,从而明确地告知调用者操作失败的原因。