栈(顺序栈和链式栈)的实现(Java)

1,385 阅读2分钟

一、栈的介绍

栈是操作受限的线性表,只能在一端进行插入和删除操作,这一端被称为栈顶。

栈是 “先进后出、后进先出” 的数据结构。

虽然被称为操作受限的线性表,但是栈有很多应用,比如函数调用栈,表达式求值,括号匹配等等。

栈的操作最主要的就是入栈与出栈;增加元素,在栈中被称为入栈;删除元素,在栈中被称为出栈

二、栈的实现

栈的底层由两种数据结构实现。

用数组实现栈被称为顺序栈

用链表实现栈被称为链式栈

(一)、顺序栈

1、入栈

入栈操作示意图:

顺序栈的底层数据结构是数组,也就是说,顺序栈的入栈实际的操作就是在数组末尾增加元素。时间复杂度为 O(1)

    /**
     * 入栈
     * @param e
     */
    public void push(int e) {
        // 判断栈是否已满,栈满无法入栈
        if (size == capacity) {
            throw new RuntimeException("栈满,无法进行入栈操作");
        }
        // 入栈操作
        data[size] = e;
        size++;
    }

data 为实际存储数据的数组,size 是数组内的元素个数,capacity 是数组的实际大小。

在上面这种情况下,如果数组已满,就不可以继续插入元素。

但是可以使用动态数组来实现可以动态扩容的顺序栈。

2、出栈

出栈示意图:

顺序栈的出栈操作实际上就是删除数组的最后一个数据元素。时间复杂度为 O(1)。

    /**
     * 出栈
     * @return
     */
    public int pop() {
        // 判断栈是否为空,栈空则无法出栈
        if (size == 0) {
            throw new RuntimeException("栈空,无法进行出栈操作");
        }
        int result = data[size - 1];
        size--;
        return result;
    }

size 是数组实际元素数量。

(二)、链式栈

1、入栈

链式栈的入栈操作其实就是在链表末尾添加元素,时间复杂度为 O(1)。

   /**
     * 入栈
     *
     * @param e
     */
    public void push(int e) {
        Node newNode = new Node(e);
        if (size == 0) {
            head = newNode;
        } else {
            Node t = head;
            // 找到单链表末尾节点
            while (t.next != null) {
                t = t.next;
            }
            // 将新节点添加到链表末尾
            t.next = newNode;
            newNode.next = null;
        }
        size++;
    }

size 为链表中的节点个数,head 存储链表头结点的内存地址。

2、出栈

链式栈的出栈操作其实就是删除链表的尾结点。时间复杂度为 O(1)。

        /**
     * 出栈
     *
     * @return
     */
    public int pop() {
        if (size == 0) {
            throw new RuntimeException("栈空,无法执行出栈操作");
        }
        int result = -1;
        if (size == 1) {
            result = head.data;
            head = null;
        } else {
            Node t = head;
            // 找到单链表的尾结点的前一个结点
            while (t.next.next != null) {
                t = t.next;
            }
            // 存储出栈元素的值
            result = t.next.data;
            // 将链表尾结点删除
            t.next = null;
        }
        size--;
        return result;
    }

三、完整代码

顺序栈

动态数组

用动态数组实现顺序栈

链式栈