数据结构(5)--栈

来源:互联网 发布:爱剪辑mac能用吗 编辑:程序博客网 时间:2024/05/16 07:43

相信大家平时在码代码的时候会经常出现StackOverflowError,这个错误就是栈溢出的错误了.而栈溢出经常是因为方法运行的时候,请求新建栈帧时
栈所剩空间小于战帧所需空间。
实例:在递归调用方法,不停产生栈帧,导致栈空间异常,抛出错误.(这时候我们应该要注意到我们递归出口否是定义了)
还有一点小知识进行拓展:
栈是一个线程私有的,通常用于保存方法(函数)中的参数,局部变量。在java中,所有基本类型和引用类型的引用都在栈中存储。栈中数据的生存空间一般在当前scopes内(就是由{…}括起来的区域)

但是,我们今天的重点不是这个.我们的重点是栈.我们接下来就认识一下栈,这么一个东西.
堆栈(也简称作栈)是一种特殊的线性表,堆栈的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置进行插入和删除操作,而堆栈只允许在固定一端进行插入和删除操作。

先进后出:堆栈中允许进行插入和删除操作的一端称为栈顶,另一端称为栈底。堆栈的插入和删除操作通常称为进栈或入栈,堆栈的删除操作通常称为出栈或退栈。(注意:这个是最大的特点:经常考试考研都会出到的)
还有以下这么几个概念:
栈:限定只在表尾进行插入和删除操作的线性表。

栈是线性表:其特殊性在于插入和删除操作必须在表尾。

空栈:栈中没有数据元素。

压栈(进栈):往栈中输入数据元素。

弹栈(出栈):从栈中输出数据元素。

栈顶:允许进行数据插入删除操作的一端是栈。

栈底:不允许进行数据插入删除操作的一端是栈。

共享栈:指有两个相同类型的顺序栈,一个栈已经满载,另一个却仍有空闲时间,为了能充分利用到未被使用的空闲空间,可以采用共享栈。

由于栈是线性表的特例,而线性表我们是采用数组实现的,而我们也用数组模拟顺序栈.

代码实现:

    /**     * 思路:     * 1. 利用数组初始化栈对象     * 2. 对栈进行安全性判断     * 3. 入栈出栈操作     * @author Administrator     *     * @param <T>     */    public class LinearStack<T> {        //初始栈的数据        private T[] data;        private int size;        private int top=-1;        //建长度为5的空栈        LinearStack() {            this(null);        }        //建长度为5,栈顶为element的栈        LinearStack(T element) {            this(element,5);        }            //1.初始化栈,自定义大小和参数对象传入        public LinearStack(T element, int size) {            if(size <= 0) {                return;            }            data = (T[]) new Object[size];            this.size = size;            if(element != null) {                data[0] = element;                top++;            }        }        //获取长度        public int getlength(){            if(top==-1){                return 0;            }else{                return top+1;            }        }        //判断是否为空        public boolean isEmpty(){            return top==-1;        }        public boolean  isFull(){            return top==size-1;        }        //压栈        /**         * 思路:         * 1. 先++拓展出一个空位         * 2. 然后再赋值         * @param element         * @return         */        public boolean Push(T element) {            if(isFull()) return false;            top++;            data[top] = element;            return true;        }        //弹栈        public T Pop() {            if(isEmpty()) return null;            T temp = data[top];            top--;            return temp;        }        //重写父类toString方法,做栈顶到栈底的遍历        public String toString() {            int len = getlength();            if(len == 0) {                return "[ ]";            }else{                //字符串拼接                StringBuffer sb = new StringBuffer();                sb.append("[ ");                for(int i = 0; i < len; i++) {                    sb.append(data[i]+" ");                }                sb.append("]");                return sb.toString();            }        }        public static void main(String[] args) {             LinearStack<String> linearStack = new LinearStack<>("1");             //去掉初始化那个吧             linearStack.Pop();             linearStack.Push("A");             linearStack.Push("B");             linearStack.Push("C");             linearStack.Push("D");             linearStack.Push("E");             System.out.println(linearStack.getlength());             linearStack.Pop();             linearStack.Pop();             System.out.println(linearStack.getlength());        }    }

当然我们还有一个是链式栈,但是实际应用中,我们更多是讨论的顺序栈,对于链式栈,就是用链式表表达栈,每一个位置用一个结点表示.大家可以到时候google一下相关的.

两者优劣势:

顺序栈和链栈的插入、删除操作时间复杂度都是O(1);

顺序栈需要事先确定数组的长度,有可能存在浪费内存空间的情况;

链栈虽然不需要事先确定表长,但因为需要存储链式指针,同时加大了内存开销;

因此,如果数据元素变化不可预测,时大时小,最好使用链栈;如果它的变化空间在可控范围内,则可以考虑使用顺序栈。

0 0