重學資料結構(二、棧)

三分惡發表於2020-08-26

@


1、棧的定義和特點

棧(Stack)又稱堆疊, 是限制在表的一端進行插入和刪除運算的線性表。

如果要拿一個東西對比,羽毛球筒比較合適。

在這裡插入圖片描述

棧遵循後進先出( Last-in-first-out,LIFO)的原則。

比如上面的羽毛球筒,只能將最頂端的羽毛球移出,也只能將新的羽毛球放到最頂端——這兩種操作分別稱作入棧( Push)出棧( Pop)。入棧和出棧的示意圖如下:

在這裡插入圖片描述

在這裡插入圖片描述

最頂端的羽毛球叫棧頂棧頂 (top),最底端的羽毛球稱為棧底 (bottom)

在這裡插入圖片描述


2、棧的基本操作

棧的基本操作除了入棧和出棧外, 還有棧的初始化、 棧空的判定, 以及取棧頂元素等。

根據這些操作,我們定義一個介面:

/**
 * @Author 三分惡
 * @Date 2020/8/26
 * @Description 棧介面
 */
public interface Stack {
    public int getSize();          //返回棧中元素數目
    public boolean isEmpty();      //判空
    public Object top();           //取棧頂元素但不刪除
    public void push(Object element);      //入棧
    public Object pop();              //出棧
}

線性表有順序和鏈式兩種實現,棧同樣有兩種實現。


3、順序棧

這裡我們通過一個可擴容的陣列來實現。

/**
 * @Author 三分惡
 * @Date 2020/8/26
 * @Description 順序棧--陣列實現
 */
public class ArrayStack implements Stack{

    private static  int defaultSize=15;   //預設容量
    private int size;                    //實際容量:實際儲存元素個數
    private Object[] data;               //存放元素的陣列

    /**
     * 無參構造方法:按預設容量構造元素陣列
     */
    public ArrayStack() {
        data=new Object[defaultSize];
        size=0;
    }

    /**
     * 有參構造方法:指定元素陣列容量
     * @param size
     */
    public ArrayStack(int size){
        data=new Object[size];
    }

    public int getSize() {
        return size;
    }

    public boolean isEmpty() {
        return size==0;
    }

    /**
     * 取棧頂元素:不刪除棧頂元素
     * @return
     */
    public Object top() {
        if (isEmpty())
            throw new RuntimeException("棧空");
        size--;
        return data[size-1];
    }

    /**
     * 入棧
     * @param element
     */
    public void push(Object element) {
        //陣列已滿,擴容
         if (size==data.length){
             //擴容兩倍的新陣列
             Object [] newData=new Object[size<<1];
             //拷貝陣列
             System.arraycopy(data,0,newData,0,size);
             data=newData;
         }
         //棧頂上插入新元素
         data[size]=element;
         size++;
    }

    /**
     * 出棧
     * @return
     */
    public Object pop() {
        if (isEmpty())
            throw new RuntimeException("棧空");
        Object top=data[size-1];
        data[size-1]=null;
        size--;
        return top;
    }
}

時間複雜度分析:

  • getSize():O(1)
  • isEmpty():O(1)
  • top():O(1)
  • push():平均O(1),最壞(擴容)O(n)
  • pop(): O(1)

3、鏈棧

鏈棧指的是鏈式儲存結構實現的棧。在前面的學習中,我們已經完成了單向連結串列的實現,程式碼如下,具體說明可檢視上一篇內容:

在這裡插入圖片描述

現在我們通過單向連結串列來實現鏈棧:

/**
 * @Author 三分惡
 * @Date 2020/8/26
 * @Description
 */
public class ListStack implements Stack{
    //單向連結串列
    private SinglyLinkedList list;

    /**
     * 建構函式:初始化單向連結串列
     */
    public ListStack(){
        list=new SinglyLinkedList();
    }

    /**
     * 獲取棧的容量
     * @return
     */
    public int getSize() {
        return list.getSize();
    }

    public boolean isEmpty() {
        return list.getSize()==0;
    }

    /**
     * 取棧頂元素
     * @return
     */
    public Object top() {
        //取列表的尾節點
        return list.get(list.getSize()-1);
    }

    /**
     * 入棧
     * @param element
     */
    public void push(Object element) {
        //佇列尾插入
       list.addTail(element);
    }

    /**
     * 出棧
     * @return
     */
    public Object pop() {
        int topIndex=list.getSize()-1;
        //列表為節點
        Object top=list.get(topIndex);
        //刪除尾結點
        list.remove(topIndex);
        return top;
    }
}

時間複雜度分析:

  • getSize():O(1)
  • isEmpty():O(1)
  • top():O(1)
  • push():O(1)
  • pop(): O(1)

4、java中的棧

在Java中有一個java.util.Stack類,它實現了棧的結構。

它是Vector的子類,也自定義了一些作為棧的方法。

在這裡插入圖片描述
java.util.Stack類是Vector的子類,實際上並不建議使用它。

在Java中還有另外一個集合,可以作為棧使用,它就是LinkedList。LinkedList中實現了push、pop方法。具體可以檢視LinkedList原始碼閱讀筆記




原始碼地址:https://gitee.com/LaughterYoung/data-structure-learn.git


上一篇:重學資料結構(一、線性表)




本文為學習筆記類部落格,主要資料來源如下!



參考:

【1】:鄧俊輝 編著. 《資料結構與演算法》
【2】:王世民 等編著 . 《資料結構與演算法分析》
【3】: Michael T. Goodrich 等編著.《Data-Structures-and-Algorithms-in-Java-6th-Edition》
【4】:嚴蔚敏、吳偉民 編著 . 《資料結構》
【5】:程傑 編著 . 《大話資料結構》
【6】:Java Stack 類

相關文章