Java最小栈的实现
最小栈一般是由两个栈构成,可以在O(1)的情况下取出栈中的最小元素
其原理如下:
有两个栈A和B,其中我们把A栈设为主栈,B栈设为辅栈
入栈规则
入栈的规则是,比较新元素和最小值的大小,如果新元素不比最小值小,则A栈直接入栈即可,如果新元素比最小值还要小,则A栈入栈的同时B栈也要将新元素的下标压入B栈
出栈规则
出栈的规则是,出栈的这个元素是不是最小栈所记录的最小元素,如果是,则A栈B栈都要出栈,若不是,则只需要A栈出栈
获取最小值
min = A[ B[top] ]
(B栈栈顶元素 等于 A栈元素中下标) 的A栈元素为最小元素
开始两栈都为空
A
B
然后我们压入第一个数据3(A栈当中3为元素的值,0为该元素的下标)
A 30
B 00
此时A栈直接压入新元素,然后将新元素的下标0压入B栈
此时B栈存的值为A栈当中最小元素的下标,即min = A[B[0]] = A[0] = 3
此时再压入一个元素4
由于4比此时最小栈的最小元素3小,直接压入A栈即可,B栈不做修改
A 30 41
B 00
最小值为min = A[B[0]] = A[0] = 3
如果此时压入一个元素2
此时将新元素与当前最小元素进行比较,由于新元素2比最小元素3还要小,所有A栈和B栈都要操作
操作为 将新元素压入A栈,然后将新元素的下标压入B栈
A 30 41 22
B 00 21
此时最小栈的最小值为min = A[B[top]] = A[2] = 2
此时我们执行出栈
由于A的栈顶元素下标为2,B的栈顶元素值也为2,所以A栈B栈都需要出栈,
A 30 41
B 00
最小值为min = A[B[0]] = A[0] = 3
我们继续执行出栈
由于A的栈顶元素下标为1,B的栈顶元素值为0,只需要将A出栈即可
A 30
B 00
现在使用Java进行最小栈的实现
首先我们定义一个栈
public class Stack {
/**
* 用来存放元素的数组指针
*/
protected Object[] elements;
/**
* 栈的最大元素数量
*/
protected Integer maxSize;
/**
* 栈的当前元素数量
*/
protected Integer size;
/**
* 构造函数
*/
public Stack(Integer maxSize){
this.elements = new Object[maxSize];
this.maxSize = maxSize;
this.size = 0;
}
/**
* 入栈
*/
public Boolean push(Object element){
if(size.equals(maxSize) || 0 < size.compareTo(maxSize) ){
return Boolean.FALSE;
}
elements[size] = element;
size++;
return Boolean.TRUE;
}
/**
* 出栈
*/
public Boolean pop(){
if(size.equals(0)){
return Boolean.FALSE;
}
size--;
return Boolean.TRUE;
}
/**
* 根据下标获取元素
* @param index 下标
*/
public Object getElement(Object index){
return getElement((Integer)index);
}
/**
* 根据下标获取元素
* @param index 下标
*/
public Object getElement(Integer index){
return index.compareTo(size) < 0 ? elements[index] : null;
}
/**
* 获得栈顶元素
*/
public Object getTopElement(){
if(!size.equals(0)){
return elements[size - 1];
}
return null;
}
/**
* 获得栈的最大元素数量
*/
public Integer getMaxSize() {
return maxSize;
}
/**
* 获得栈的当前元素数量
*/
public Integer getSize() {
return size;
}
}
利用这个栈我们来设计一个最小栈
public class MinStack {
/**
* 主栈
*/
protected Stack mainStack;
/**
* 辅栈
*/
protected Stack helpStack;
/**
* 自定义比较规则(CustomRules是一个自定义接口,代码在MinStack类下面)
*/
protected CustomRules customRules;
/**
* 默认比较规则
*/
protected Boolean defaultLessThan(Object a,Object b){
return Double.valueOf(a.toString()) < Double.valueOf(b.toString());
}
/**
* 设置比较规则
*/
public void setCustomRules(CustomRules customRules){
this.customRules = customRules;
}
/**
* 构造最小栈
*/
public MinStack(Integer maxSize){
mainStack = new Stack(maxSize);
helpStack = new Stack(maxSize);
customRules = null;
}
/**
* 获得最小元素
*/
public Object getMinElement(){
if(mainStack.getSize().equals(0)){
return null;
}
return mainStack.getElement(helpStack.getTopElement());
}
/**
* 获得栈顶元素
*/
public Object getTopElement(){
return mainStack.getTopElement();
}
/**
* 入栈
*/
public synchronized Boolean push(Object object){
if(mainStack.push(object)){
/*
* 主栈入栈成功
*/
if(mainStack.getSize().equals(1)){
/*
* 主栈入栈之前是空栈,则说明B栈也是空栈,所以B栈直接把0入栈即可
*/
helpStack.push(0);
}
else {
/*
* 入栈前已经有元素存在,所以要把新元素和原最小元素进行比较
*/
Boolean less;
/*
* 此时判断customRules是否为null
*/
if(null == customRules){
/*
* 说明用户没有调用setCustomRules函数,调用默认比较函数进行大小比较
*/
less = defaultLessThan(object,mainStack.getElement(helpStack.getTopElement()));
}
else {
/*
* 说明用户调用过setCustomRules函数,调用用户自定义的比较函数进行大小比较
*/
less = customRules.lessThan(object,mainStack.getElement(helpStack.getTopElement()));
}
if(less){
/*
* 如果新元素比原最小元素还小,则将新元素在主栈的下标压入辅栈
*/
helpStack.push(mainStack.getSize() - 1);
}
}
return Boolean.TRUE;
}
return Boolean.FALSE;
}
/**
* 出栈
*/
public synchronized Boolean pop(){
if(mainStack.pop()){
/*
* 主栈出栈成功
*/
if(mainStack.getSize().equals(helpStack.getTopElement())){
/*
* 主栈出栈的元素的下标 == 辅栈的栈顶元素值
* 辅栈也要出栈
*/
helpStack.pop();
}
return Boolean.TRUE;
}
return Boolean.FALSE;
}
/**
* 获得最小栈当前的元素数量
*/
public Integer getSize(){
return mainStack.size;
}
/**
* 获得最小栈所允许的最大元素数量
*/
public Integer getMaxSize(){
return mainStack.maxSize;
}
}
/**
* 自定义比较规则接口
*/
public interface CustomRules {
Boolean lessThan(Object a,Object b);
}
接下来进行测试
public class App {
public static void main(String[] args){
MinStack minStack = new MinStack(100);
/*
* []
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
minStack.push(3);
/*
* [3]
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
minStack.push(5);
/*
* [3,5]
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
minStack.push(4);
/*
* [3,5,4]
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
minStack.push(1);
/*
* [3,5,4,1]
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
minStack.push(6);
/*
* [3,5,4,1,6]
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
minStack.pop();
/*
* [3,5,4,1]
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
minStack.pop();
/*
* [3,5,4]
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
minStack.pop();
/*
* [3,5]
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
minStack.pop();
/*
* [3]
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
minStack.pop();
/*
* []
*/
System.out.println("当前最小元素为 " + minStack.getMinElement());
}
}
在jdk8下运行的结果为
当前最小元素为 null
当前最小元素为 3
当前最小元素为 3
当前最小元素为 3
当前最小元素为 1
当前最小元素为 1
当前最小元素为 1
当前最小元素为 3
当前最小元素为 3
当前最小元素为 3
当前最小元素为 null
符合预期
但是我们这个栈不止是可以放数字的,自然也可以放复杂对象,那么放了复杂对象怎么办呢?只需要调用setCustomRules函数自定义比较规则即可
首先我们定义一个复杂对象User
public class User{
public String name;
public Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试代码
public class App {
public static void main(String[] args){
MinStack minStack = new MinStack(100);
/*
* 自定义比较规则
* 规则为如果一个User的age比较小,则这个User比较小
*/
minStack.setCustomRules((Object a,Object b)->{
User aUser = (User)a;
User bUser = (User)b;
return aUser.age.compareTo(bUser.age) < 0 ? Boolean.TRUE : Boolean.FALSE;
});
System.out.println(minStack.getMinElement());
minStack.push(new User("张三",20));
System.out.println(minStack.getMinElement());
minStack.push(new User("李四",21));
System.out.println(minStack.getMinElement());
minStack.push(new User("王五",19));
System.out.println(minStack.getMinElement());
minStack.pop();
System.out.println(minStack.getMinElement());
minStack.pop();
System.out.println(minStack.getMinElement());
minStack.pop();
System.out.println(minStack.getMinElement());
}
}
运行结果为
null
User{name=‘张三’, age=20}
User{name=‘张三’, age=20}
User{name=‘王五’, age=19}
User{name=‘张三’, age=20}
User{name=‘张三’, age=20}
null
符合预期
至此,一个简单的最小栈完成