天天看點

Stack源碼分析底層資料結構構造方法進棧獲得棧頂元素出棧查詢元素在棧中位置(下标)linkedList實作棧

文章目錄

  • 底層資料結構
  • 構造方法
  • 進棧
  • 獲得棧頂元素
  • 出棧
  • 查詢元素在棧中位置(下标)
  • linkedList實作棧
    • 底層資料結構
    • 進棧
    • 出棧
    • 獲得棧頂元素
    • 是否是空棧

之前我們看過Vector,知道Vector是基于數組實作的,本文我們來看看Stack(棧)這種資料結構

棧是一種先進後出的資料結構,可以基于數組實作,也可以基于連結清單實作

java集合中的Stack是基于Vector實作的,對于Vector可以具體看Vector源碼分析

public
class Stack<E> extends Vector<E> 
           

底層資料結構

因為是基于Vector實作,是Vector的子類,是以同樣,Stack的底層資料結構是數組

public
class Stack<E> extends Vector<E> 

protected Object[] elementData;
           

構造方法

隻有一個預設的無參構造方法,調用構造一個空棧

public Stack() {
    }
           

進棧

進棧操作操作的數組的末端,數組的末端相當于棧頂

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

        return item;
    }
           

調用的是vector的添加元素的方法,預設是數組末端添加

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

獲得棧頂元素

peek()方法是線程安全的,也使用到了同步關鍵字,通過數組下标直接定位到棧頂元素,進而擷取

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

        if (len == 0)
            throw new EmptyStackException();
        //通過數組下标直接定位到棧頂元素    
        return elementAt(len - 1);
    }

    //傳回目前數組元素個數,這是Vector的API,在這裡是棧中元素個數
    public synchronized int size() {
        return elementCount;
    }

    //Vector的API,根據下标擷取值
    public synchronized E elementAt(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
        }

        return elementData(index);
    }
           

出棧

也是調用Vector的API直接點根據下标删除棧頂元素

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

        //擷取棧頂元素,傳回用
        obj = peek();
        //根據下标删除棧頂元素
        removeElementAt(len - 1);

        return obj;
    }

    //也是調用Vector的API直接點根據下标删除棧頂元素
    public synchronized void removeElementAt(int index) {
        modCount++;
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                     elementCount);
        }
        else if (index < 0) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        int j = elementCount - index - 1;
        if (j > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, j);
        }
        elementCount--;
        elementData[elementCount] = null; /* to let gc do its work */
    }
           

查詢元素在棧中位置(下标)

public synchronized int search(Object o) {
        //從後往前找,在這裡可以看做從棧頂往棧底
        int i = lastIndexOf(o);

        if (i >= 0) {
            return size() - i;
        }
        return -1;
    }

    //第二個參數是查詢的開始下标
    public synchronized int lastIndexOf(Object o) {
        return lastIndexOf(o, elementCount-1);
    }

    public synchronized int lastIndexOf(Object o, int index) {
        if (index >= elementCount)
            throw new IndexOutOfBoundsException(index + " >= "+ elementCount);

        if (o == null) {
            for (int i = index; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = index; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
           

上面就是jdk中Stack的源碼,Stack在jdk中是基于順序存儲結構的數組實作的,也可以基于雙向連結清單的LinkedList實作,下邊看看如何用LinkedList實作棧

linkedList實作棧

底層資料結構

List<Integer> list;

    /** Initialize your data structure here. */
    public MyStack() {
       list = new LinkedList<>();
    }
           

進棧

進棧操作中,Vector操作的是數組末端,那麼linkedList也很類似,操作的是尾節點,連結清單末端就是棧頂

/** Push element x onto stack. */
    public void push(int x) {
        list.add(x);
    }

    public boolean add(E e) {
        linkLast(e);
        return true;
    }
           

出棧

public int pop() {
       int length = list.size();
       return list.remove(length);
    }
    
    //找到相關節點後,删除節點,解除連結關系
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }
           

獲得棧頂元素

public int top() {
        int length = list.size();
        return list.get(length);
    }

    //通過下标找到相關節點後擷取節點值
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
           

是否是空棧

public boolean empty() {
        return list.isEmpty();
    }
           

繼續閱讀