Java最小栈的实现

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

符合预期

至此,一个简单的最小栈完成

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值