首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

【老鸟学算法】包孕 min函数的栈设计——java实现

2013-09-11 
【老鸟学算法】包含 min函数的栈设计——java实现要求:1. 定义栈的数据结构,要求添加一个 min函数,能够得到栈

【老鸟学算法】包含 min函数的栈设计——java实现
要求:
1. 定义栈的数据结构,要求添加一个 min函数,能够得到栈的最小元素。
2. 要求函数 min、push 以及 pop 的时间复杂度都是 O(1)。

这是考验“栈”数据结构设计。众所周知,栈是一种“后进先出”的线性数据结构,其push和pop的操作都是在栈顶实现的,时间复杂度为O(1),不难设计。关键是min函数,要求时间复杂度为O(1),略有难度。

难点在于,我们一方面入栈的时候,要比较得到当前栈最小值,另一方面出栈的时候,要考虑出栈元素是否为当前栈最小值。这样,就不能简单的使用一个存储空间存放当前的最小值了。

一开始我的想法是在栈内创建两个数组,一个是当做栈操作的存储数组,一个是放从大到小排序的值数组。这个“从大到小排序的值数组”不仅消耗空间,而且由于要排序,导致push操作的时间复杂度变成O(n)。

后来,偷偷搜了下,发现July同学的解法很好:自定义栈内,另建一个栈,用于存储最小值的数组下标。即,入栈时,通过最小值索引栈,得到当前最小值下标,取数组对应值,如果比入栈的当前值大,则将当前值入栈下标,压入到索引栈中;出栈时,若当前出栈值的索引为索引栈的栈顶元素,则索引栈也进行栈顶元素出栈操作。

其它push、pop操作都比较传统,也很简单,不赘述了。

java实现,自然而然想到泛型的使用了。这里的泛型也是有要求的:必须实现Compareable接口。

接下来就是源码了。这里保留原先min笨方法的实现,注释掉了,大家可以对比看看。

import java.util.Stack;/** * 自定义栈 * @author oh_Maxy */public class MyStack<E>{    private int size = 16;//默认规模    private int nextSize = 16;//超过范围,扩展操作    private Object[] valArr;//存储数据结构    //private Object[] minArr;//存储顺序排序//笨办法    private int index = -1;//栈顶下标    private Stack<Integer> minStack;//存储最小值下标的栈//参考July的方法    /**     * 构造器     */    public MyStack()    {        valArr = new Object[size];        //minArr = new Object[size];//笨办法        minStack = new Stack<Integer>();    }    /**     * 入栈     * @param value     */    public void push(E value)    {        //不能为空        if (null == value)        {            throw new NullPointerException("Pushed value can not be null!");        }        //入参必须为可比较的        if (!(value instanceof Comparable))        {            throw new UnsupportedOperationException("The value must be Comparable!");        }        //栈满了,重构栈        if (index >= size)        {            resetStack();        }        //入栈        valArr[++index] = value;        //最小值插入排序        //putMinObj(value);//笨办法        //最小值的索引入栈        checkMinObj(value);    }    /**     * 笨办法     * 将push的值插入minArr中     * @param value     */    /*private void putMinObj(E value)    {        Comparable valueComp = (Comparable) value;        int i = index;        for (; i > 0; i--)        {            if (valueComp.compareTo(minArr[i - 1]) < 0)            {                minArr[i] = valueComp;                break;            }            minArr[i] = minArr[i - 1];        }        //push的值为最大值,放在首位        if (i == 0)        {            minArr[0] = valueComp;        }    }*/    /**     * 参考July的最小索引入栈思想     * @param value     */    @SuppressWarnings("unchecked")    private void checkMinObj(E value)    {        //第一个参数,直接为最小参数        if (index == 0)        {            minStack.push(index);            return;        }        //入参的值        Comparable valueComp = (Comparable) value;        //当前最小值        Comparable valueMinComp = (Comparable) valArr[minStack.peek()];        //新入栈的值小于当前最小值,则当前索引入栈        if (valueComp.compareTo(valueMinComp) < 0)        {            minStack.push(index);        }    }    /**     * 出栈     */    @SuppressWarnings("unchecked")    public E pop()    {        //栈为空,报错        if (index < 0)        {            throw new NullPointerException("The statck is empty!");        }        //若是最小值出栈(比较下标判断),需要将其索引出栈        if (index == minStack.peek())        {            minStack.pop();        }        //出栈        return (E) valArr[index--];    }    /**     * 最小值     */    @SuppressWarnings("unchecked")    public E getMin()    {        //return (E) minArr[index];//笨办法        //若栈空,则报错空指针        if (index < 0)        {            throw new NullPointerException("The statck is empty,no minValue returned!");        }        return (E) valArr[minStack.peek()];    }    /**     * 重构栈     */    private void resetStack()    {        size += nextSize;        Object[] newArr = new Object[size];        System.arraycopy(valArr, 0, newArr, 0, size - nextSize);        valArr = newArr;    }    //测试桩    public static void main(String[] args)    {        //栈初始化//也可以直接使用Integer等实现了Comparable接口的封装类        MyStack<MyValue> stack = new MyStack<MyValue>();        //初始化几个值        MyValue v1 = new MyValue(1);        MyValue v2 = new MyValue(2);        MyValue v3 = new MyValue(3);        MyValue v4 = new MyValue(4);        MyValue v5 = new MyValue(5);        //入栈        stack.push(v5);        stack.push(v4);        stack.push(v3);        stack.push(v2);        stack.push(v1);        stack.push(v4);        stack.push(v1);        //最小值        System.out.println("min: " + stack.getMin());        //出栈        System.out.println("pop: " + stack.pop());        System.out.println("min: " + stack.getMin());        System.out.println("pop: " + stack.pop());        System.out.println("min: " + stack.getMin());        System.out.println("pop: " + stack.pop());        System.out.println("min: " + stack.getMin());        System.out.println("pop: " + stack.pop());        System.out.println("min: " + stack.getMin());        System.out.println("pop: " + stack.pop());        //最小值        System.out.println("min: " + stack.getMin());        System.out.println("min: " + stack.getMin());        System.out.println("pop: " + stack.pop());        System.out.println("min: " + stack.getMin());        System.out.println("pop: " + stack.pop());    }}/** * 自定义数值类 */class MyValue    implements Comparable<MyValue>{    private int value;    public MyValue(int value)    {        this.value = value;    }    public int getValue()    {        return value;    }    public int compareTo(MyValue obj)    {        //不能与null比较        if (null == obj)        {            throw new NullPointerException("Can not compare to null!");        }        return this.value - obj.getValue();    }    @Override    public String toString()    {        return "" + value;    }}

除了数据结构的实现,关于这个类的设计思想,也有两点值得关注的地方:
1. 泛型的使用;
2. 运行时异常的使用;

欢迎斧正。


热点排行