数据结构(5)--栈

相信大家平时在码代码的时候会经常出现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);

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值