資料結構基礎學習之(棧和佇列)

h_dj發表於2019-04-05

主要學習知識點

  • 棧的概念及其抽象資料型別描述
  • 順序棧類和鏈棧的描述和實現
  • 佇列的概念及其抽象資料型別描述
  • 順序迴圈佇列類和鏈佇列類的描述與實現

一、棧

1. 概念:
  • 棧的定義: 棧(Stack)是限制僅在表的一端進行插入和刪除運算的線性表。
  • 通常稱插入、刪除的這一端為棧頂(Top),另一端稱為棧底(Bottom)。
  • 當表中沒有元素時稱為空棧。
  • 棧為後進先出(Last In First Out)的線性表,簡稱為LIFO表。
2. 棧的抽象資料介面
public interface IStack<E> {
    public void clear();//清空棧
    public boolean isEmpty();//是否空棧
    public int size();//棧資料元素的個數
    public E peek();//讀取棧頂元素
    public void push(E e);//進棧
    public E pop();//出棧,並返回該元素。
}
複製程式碼
3. 順序儲存結構及實現

3.1棧及其操作示意圖.png

3.2順序棧儲存結構.png

  1. 入棧操作
  • 注意:

    • 順序棧為空的條件是 top == 0
    • 順序棧滿的條件尾 top == stackElem.length
    • 棧的長度為top
    • 棧頂元素的下標為 top -1
  • 入棧示意圖

    3.3入棧操作的相應變化.png

  • 具體實現

public void push(E e) {
        //檢查棧是否已滿
        if (top == elementData.length)
            throw new RuntimeException("棧已滿!");
        //儲存元素
        elementData[top] = e;
        //棧頂指標 加一
        top++;
    }
複製程式碼
  1. 出棧操作
  • 示意圖
    3.4出棧操作.png
  • 具體實現
// 獲取棧頂元素
public E peek() {
        //判斷是否為空棧
        if (isEmpty())
            throw new RuntimeException("棧為空!");
        return (E) elementData[top - 1];  //返回棧頂元素;
    }

//出棧
public E pop() {
        E peek = peek();
        //置空出棧元素
        elementData[top - 1] = null;
        //棧頂指標減一
        top--;
        return peek;
    }
複製程式碼
  1. 順序棧完整程式碼
4. 鏈式棧及其實現

3.5鏈式棧儲存結構.png

  1. 入棧操作
  • 示意圖

    3.6鏈棧入棧示意圖.png

  • 程式碼實現

 public void push(E e) {
        //建立節點
        LNode node = new LNode(e);
        //修改棧頂指標
        node.next = top;
        top = node;
        //棧長度加一
        length++;
    }
複製程式碼
  1. 出棧操作
  • 示意圖

    3.7鏈棧出棧示意圖.png

  • 程式碼實現

//獲取棧頂元素
public E peek() {
        if (isEmpty())
            throw new RuntimeException("棧為空!");
        return top.data;
    }

//出棧
 public E pop() {
        //獲取棧頂元素
        E pop = peek();
        //修改棧頂指標
        top = top.next;
        //棧長度減一
        length--;
        return pop;
    }
複製程式碼
  1. 鏈式棧完整原始碼

二、佇列

1. 定義:

  • 佇列(Queue)是隻允許在一端進行插入,而在另一端進行刪除的運算受限的線性表
  • 佇列亦稱作先進先出(First In First Out)的線性表,簡稱為FIFO表。

3.15佇列及其操作示意圖.png

2. 佇列抽象介面定義

/**
 * 佇列介面
 */
public interface IQueue<T> {

    void clear();//清空佇列
    boolean isEmpty();//判斷空佇列
    int size();//佇列長度
    T peek(); //讀取隊首元素
    void offer(T t);//入佇列
    T poll();//出佇列
}
複製程式碼
3. 順序佇列及其實現
  1. 出入佇列示意圖

3.16順序佇列入出佇列示意圖.png

  1. 假溢現象

出現原因:

  • 如出入佇列的示意圖
  • 在初始化一個長度為6的佇列
  • 先入佇列A、B、C,然後A、B又出佇列,造成對頭有兩個位置空置
  • 接著E、F、G入隊後,如果想H入隊,這時必定會引起陣列越界異常
  • 佇列有空間,但不能入隊的溢位現象稱為假溢現象

解決方式:

  • 採用首尾相連的迴圈順序佇列,避免出現出隊後空出儲存空間

迴圈順序佇列的四種狀態圖

3.17迴圈順序佇列的四種狀態圖.png

  1. 解決無法區分隊空和隊滿的狀態問題(front: 隊首指標,rear:隊尾指標, maxSize:容量大小)

方法一、採用少存一個儲存單元的方法

  • 隊空判斷條件為: front == rear
  • 隊滿判斷條件:front == (rear+1) % maxSize

3.18少用一個儲存單元實現迴圈佇列的方式.png

設定一個標誌變數:flag, 其初始值為flag = 0, 入隊flag = 1, 出佇列flag = 0

  • 隊空判斷條件為: front == rear && flag == 0
  • 隊滿判斷條件:front == rear && flag == 1

設定一個計數器: length , 入隊length ++; 出隊length--

  • 隊空判斷條件為: length == 0
  • 隊滿判斷條件:length >0 && front == rear
  1. 採用方法一實現的順序迴圈佇列原始碼
4. 鏈式佇列及其實現
  1. 示意圖

    3.19鏈式佇列儲存結構.png

  2. 入佇列操作

    3.20鏈式佇列入佇列操作.png

  • 程式碼實現
   public void offer(T t) {
        // 建立節點
        LNode<T> node = new LNode<T>(t);
        //判斷佇列是否為空,空則賦值為隊首和隊尾指標
        if (isEmpty()) {
            front = rear = node;
        } else {
            //不為空,則插入隊尾
            //佇列的尾節點的指標指向新節點
            rear.next = node;
            //尾指標指向新節點,作為新尾節點4
            rear = node;
        }
        //長度加一
        ++length;
    }
複製程式碼
  1. 出佇列
//獲取隊首元素
public T peek() {
        //判斷是否為空佇列
        if (isEmpty())
            throw new RuntimeException("佇列為空!");
        return front.data;
    }

//出佇列
public T poll() {
        //獲取隊首元素
        T poll = peek();
        //修改隊首指標
        this.front = this.front.next;
        //長度減一
        --length;
        //返回資料
        return poll;
    }
複製程式碼
  1. 鏈式佇列完整原始碼實現
  2. 優先順序佇列及其實現

三、 棧和佇列的區別

相同點

  1. 都是線性結構,元素之間具有“一對一”的邏輯關係
  2. 插入操作都是再表尾進行
  3. 都可以使用順序儲存結構或鏈式儲存結構實現
  4. 在時間代價上,插入刪除操作的時間複雜度都是O(1), 在空間待見上也相同

不同點

  1. 刪除操作的位置不同,棧只在表尾操作,佇列在表頭操作
  2. 棧是後進先出(LIFO),佇列是先進先出(FIFO),應用場景不同
  3. 順序棧可以多棧空間共享,而順序佇列不同

相關文章