(二)数据结构之栈

2018-12-01  本文已影响0人  纸中圆

思维导图

什么是栈:

  堆栈(英语:stack)又称为堆叠,是计算机科学中一种特殊的串列形式的抽象数据类型,其特殊之处在于只能允许在链表数组的一端(称为堆栈顶端指针,英语:top)进行加入数据(英语:push)和输出数据(英语:pop)的运算。另外堆栈也可以用一维数组链表的形式来完成。堆栈的另外一个相对的操作方式称为队列

特点:

•栈也是一种线性结构
•相比数组,栈对应的操作是数组的子集
•只能从一端添加元素,也只能从一端取出元素
•由于堆栈数据结构只允许在一端进行操作,因而按照后进先出(LIFO, Last In First Out)的原理运作。

操作:

堆栈数据结构使用两种基本操作:推入(压栈,push)和弹出(弹栈,pop):

推入:将数据放入堆栈的顶端(数组形式或串列形式),堆栈顶端top指针加一。
弹出:将顶端数据数据输出(回传),堆栈顶端数据减一。

图示:

代码实现:

从上文我们知道栈的功能属于数组的一部分,我们可以调用第一篇文章实现的数组来实现栈的代码,但是数组有的功能栈用不到,所以我们不采用这种方法,而是直接写,当然你觉得那样更简单也可以直接在栈的代码中调用数组中的代码,下面代码也是使用泛型实现,以后均是。

public class ArrayStack<E> implements Stack<E> {
    E[] arraystack;
    int size;//栈元素个数

    /**
     * capacity为栈初始容量
     *
     * @param capacity
     */
    public ArrayStack(int capacity) {
        arraystack = (E[]) new Object[capacity];
    }

    //初始容量默认为10
    public ArrayStack() {
        this(10);
    }

    //判断栈是否为空
    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    //获取栈元素个数
    @Override
    public int size() {
        return size;
    }

    //获取栈的容量大小
    public int getCapacity() {
        return arraystack.length;
    }

    //指定元素压栈
    @Override
    public void push(E e) {
        if (size == arraystack.length) {
            throw new IllegalArgumentException("arrayStack is full");
        }
        arraystack[size] = e;
        size++;
    }

    //栈顶元素出栈
    @Override
    public E pop() {
        if (size == 0) {
            throw new IllegalArgumentException("No element,pop is failed");
        }
        E e = arraystack[size - 1];
        arraystack[size - 1] = null;
        size--;
        return e;
    }

    //查看栈顶元素
    @Override
    public E peek() {
        return arraystack[size - 1];
    }

    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        res.append(String.format("Stack size = %d ,capacity = %d\n", size, arraystack.length));
        res.append('[');
        for (int i = 0; i < size; i++) {
            res.append(arraystack[i]);
            if (i != size - 1) {
                res.append(',');
            }
        }
        res.append(']');
        return res.toString();
    }
}

为了使该栈能动态增减,加入以下优化:

//将旧栈指向一个新栈(新栈长度可以自定义)
    public void resize(int newCapacity){
        E[] newArrayStack =(E[])new Object[newCapacity];
        for (int i = 0; i < size; i++) {
            newArrayStack[i] = arraystack[i];
        }
        arraystack = newArrayStack;
    }

push代码优化:

//指定元素压栈
    @Override
    public void push(E e) {
        if (size == arraystack.length) {
            //元素满栈则将栈扩容(容量为旧栈2倍)
            resize(2 * arraystack.length);
        }
        arraystack[size] = e;
        size++;
    }

pop代码优化:

 //栈顶元素出栈
    @Override
    public E pop() {
        if (size == 0) {
            throw new IllegalArgumentException("No element,pop is failed");
        }
        E ret = arraystack[size - 1];
        arraystack[size - 1] = null;
        size--;
        //如果栈元素个数为容量的四分之一(考虑到复杂度震荡),将该栈指向一个新栈(容量为旧栈一半)
        if(size == arraystack.length / 4 && arraystack.length / 2 !=0){
            resize(arraystack.length / 2);
        }
        return ret;
    }

测试结果:


链表实现栈代码:

public class LinkedListStack<E> implements Stack<E>{
    LinkedList<E> linkedList = new LinkedList<>();

    public int getSize() {
        return linkedList.getSize();
    }

    public boolean isEmpty() {
        return linkedList.isEmpty();
    }

    public void push(E e){
       linkedList.addFirst(e);
    }


    public E pop() {
        return linkedList.removeFirst();
    }

    public E peek() {
        return linkedList.getFirst();
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append("LinkedListStack top:");
        res.append(linkedList);
        return res.toString();
    }
}

测试结果:

时间复杂度(上述2者相同):

上一篇 下一篇

猜你喜欢

热点阅读