java數據結構 -- Stack源碼解析

1、棧初識

Stack類是jdk中java.util包下的一個類。其方法有
Stack類的方法
棧是一種用於存儲數據的簡單數據結構,與普通的線性表不同,線性表是先進先出,即FIFO,但是棧是先進後出,即FILO。我們一般只能對棧頂元素進行操作。

2、Stack類的繼承關係接口實現

繼承與接口實現
Stack繼承了Vector類,Vector類又實現了List接口。

3、Stack類的特點

3.1 構造函數

從源碼中瞭解到,Stack類只有一個無參構造函數

    /**
     * Creates an empty Stack.
     */
    public Stack() {
    }

所以,我們無法像ArrayList或者HashMap那樣,初始化指定棧的容量大小。那麼棧的初識化容量是多少呢?什麼時候進行擴容呢?擴容的默認容量是多少呢?
由於Stack繼承了Vector類,在Vector類的源碼中可以看出:

    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }
    
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    public Vector() {
        this(10);
    }

可以看到,如果我們不指定vector的容量大小,那麼初始化的默認容量就是10。這和ArrayList的初始化容量一致。
那麼何時擴容呢?Stack的push()方法如下

public E push(E item) {
        addElement(item);

        return item;
    }

Stack直接調用了Vector類的addElement(E item)方法

public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }

private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

可以看到,是在計算插入數據後容量大小與原來容量大小做比較,除非棧滿了,纔會進行擴容。擴容調用的就是grow(minCapacity)

 private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

可以看到,如果沒有指定每次擴容的容量大小,默認的新容量將會是兩倍的舊容量。
這一點與我們熟知的ArrayList的擴容大小不一樣,ArrayList的新容量大小是舊容量加上舊容量的值的值右移一位。即
newCapacity=oldCapacity+(oldCapacity>>1)newCapacity=oldCapacity+(oldCapacity>>1)

3.2 pop與peek

 public synchronized E pop() {
        E       obj;
        int     len = size();

        obj = peek();
        removeElementAt(len - 1);

        return obj;
    }
    
  public synchronized E peek() {
        int     len = size();

        if (len == 0)
            throw new EmptyStackException();
        return elementAt(len - 1);
    }

這兩個方法都加鎖了,是線程安全的操作。
pop操作當中包含了peek操作,pop是返回棧頂元素,並將該元素從棧中刪除。而peek只返回棧頂元素,不刪除。
棧的底層數據結構用的是數組。

4、應用

棧的一些應用主要就是運用其先進後出的特性,比較典型的應用就是表達式計算,包括中綴表達式、後綴表達式以及符號匹配等等。
先留個坑,有空再填。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章