2020數據結構-棧和隊列

一、棧和隊列

1.棧

1.1 棧的基本概念

  • 定義:棧是一種線性表,只允許在一端進行插入或者刪除操作的線性表。
  • 棧頂:線性表允許進行插入刪除的一端。
  • 棧底:固定的,不允許進行插入和刪除。
  • 空棧:不含任何元素的空表。
  • 棧的操作特性是後進先出

1.2 棧的順序存儲結構

  • 順序棧的實現:採用順序存儲的棧稱爲順序棧,它利用一組連續的存儲單元存放自棧底到棧頂的數據元素,同時附設一個指針(top)指示當前棧頂的位置。
    • 棧頂指針:S.top,初始設置S.top = -1,棧頂元素:S.data[S.top]。
    • 進棧操作:棧不滿時,棧頂指針先+1,再把值傳入棧。
    • 出棧操作:棧非空時,先取棧頂元素,然後指針再-1。
    • 棧空條件:S.top == -1;棧滿條件:S.top == MaxSize -1;棧長:S.top + 1。
  • 順序棧的基本操作
    • 初始化:
    • 棧判空:
    • 進棧:
    • 出棧:
    • 讀棧頂元素:
  • 共享棧:利用棧底位置相對不變性,可以讓兩個順序棧共享 一個一維數組空間,將兩個棧的棧底分別設置在共享空間的兩端,兩個棧頂向共享空間的中間延伸。
    在這裏插入圖片描述
  • 當兩個棧的棧頂指針都指向棧頂元素時,top0 = -1時0號棧爲空,top1 = MaxSize時1號棧爲空;僅當兩個棧頂指針相鄰(top1-top0 = 1)時,判斷爲棧滿。當0號棧進棧時top0先加1再賦值,1號棧進棧時top1先減1再賦值;出棧剛好相反。

1.3 棧的鏈式存儲結構

  • 採用鏈式存儲結構的棧稱爲鏈棧
  • 鏈棧的優點:便於多個棧共享存儲空間和提高效率,不存在棧滿上溢的情況。
  • 通常採用單鏈表實現,規定所有操作都在單鏈表的表頭進行,鏈棧沒有頭結點,Lhead指向棧頂元素。
  • 鏈棧的操作與鏈表類似,對於帶頭結點的鏈棧和不帶頭結點的鏈棧,在具體實現方面有所不同。

2.隊列

2.1 隊列基本概念

  • 定義:簡稱隊,是一種操作受限的線性表,只允許在表的一端進行插入,在表的另一端進行刪除。
  • 向隊列中插入元素稱爲入隊或進隊,刪除元素稱爲出隊或離隊
  • 操作特性時先進先出
  • 隊頭:允許刪除的一端,又稱隊首
  • 隊尾:允許插入的一端。
  • 空隊列:不含任何元素的空表。

2.2 順序存儲結構

  • 順序存儲:分配一塊連續的存儲單元存放隊列中的元素,並附設兩個指針front和rear分別指示隊頭和隊尾元素的位置;設隊頭指針指向隊頭元素,隊尾指針指向隊尾元素的下一個位置(也可以讓隊尾指針指向隊尾元素,隊頭指針指向隊頭的前一個位置)。

    • 初始狀態(隊空條件):Q.front == Q.rear == 0。
    • 進隊操作:隊不爲滿時,先送值到隊尾元素,再將隊尾指針+1。
    • 出隊操作:隊不爲空時,先取隊頭元素值,再將隊頭指針+1。
    • 在隊列的初始狀態可以使用Q.front == Q.rear == 0來進行判空操作,但是不可以使用Q.rear == MaxSize進行判滿操作,因爲最開始Q.rear就是指向MaxSize的位置,此時拿這個爲判斷條件的話,再插入數值便會溢出,但是這個是”假溢出“。
  • 循環隊列:將順序隊列臆造爲一個環狀的空間,即把存儲隊列元素的表從邏輯上視爲一個環,稱爲循環隊列。當隊首指針Q.front = MaxSize-1後,再前進一個位置就自動到0,這可以利用除法取餘運算來實現。

    • 初始時:Q.front = Q.rear = 0;
    • 隊首指針進1:Q.front = (Q.front+1)%MaxSize。
    • 隊尾指針進1:Q.rear = (Q.rear+1)MaxSize。
    • 隊列長度:(Q.rear+MaxSize-Q.front)&MaxSize。
    • 出隊入隊時:指針都是按照順時針方向進1。
    • 隊空的條件時Q.front = Q.rear,當入隊元素的速度超過出隊元素的速度時,隊尾指針很快就會趕上隊首指針,此時隊滿時也有Q.front = Q.rear。
  • 爲了區分隊空還是隊滿,有三種處理方式:

    • 犧牲一個單元來區分,入隊時少用一個隊列單元,“這是一種較爲普遍的做法”,約定以“隊頭指針在隊尾指針的下一個位置作爲隊滿的標誌”。
      • 隊滿條件:(Q.rear+1)%MaxSize == Q.front。
      • 隊空條件:Q.front = Q.rear。
      • 隊列中元素的個數:(Q.rear - Q.front+MaxSize)%MaxSize。
    • 隊列中增設表示元素個數的數據成員。這樣隊空的條件爲Q.size == 0;隊滿的條件爲Q.size == MaxSize。這兩種情況都有Q.rear = Q.front。
    • 類型中增設tag數據成員,以區分是隊滿還是隊空。tag = 0時,若因刪除導致Q.front == Q.rear,則爲隊空;tag等於1時,若因插入導致Q.rear == Q.front,則爲隊滿。
  • 循環隊列的操作;

    • 初始化:
    • 判隊空
    • 入隊
    • 出隊

2.3 隊列的鏈式存儲結構

  • 隊列的鏈式存儲:稱爲鏈隊列,實際上是一個同時帶有隊頭指針和隊尾指針的單鏈表,頭指針指向隊頭結點,尾指針指向隊尾結點,即單鏈表的最後一個結點。
    在這裏插入圖片描述
  • 當Q.front == NULL且Q.rear == NULL時,鏈式隊列爲空。
  • 出隊時首先判斷是否爲空,若不爲空,則取出隊頭元素,將其從表中刪除,並讓Q.front指向下一個結點(若該結點爲最後一個結點,則Q.fornt和Q.rear都爲NULL)。
  • 入隊時,建立一個新結點,將新結點插入鏈表的尾部,並改讓Q.rear指向這個新結點(若原隊爲空則令Q.front也指向該結點)。
  • 用單鏈表表示的鏈式隊列適合於數據元素變動比較大的情形,而且不存在隊列滿且溢出的問題。

2.4 雙端隊列

  • 雙端隊列是指允許兩端都可以進行入隊和出隊操作的隊列。其元素的邏輯結構仍是線性結構。將隊列的兩端分別稱爲前端後端,兩端都可以入隊和出隊。
    在這裏插入圖片描述
  • 在雙端隊列進隊時,前端進入的元素排列在隊列中後端進的元素的前面。出隊時,無論前後端,先出的元素排列在後出的元素的前面。
  • 輸出受限制的雙端隊列:允許在一端進行插入和刪除,但在另一端只允許插入的雙端隊列稱爲輸出受限制的雙端隊列。
    在這裏插入圖片描述
  • 輸入受限的雙端隊列:允許在一端進行插入和刪除,但在另一端只允許刪除的雙端隊列稱爲輸入受限制的雙端隊列。如圖。若限定雙端隊列從某個斷點插入的元素只能從該端點刪除,則該雙端隊列就蛻變爲兩個棧底相鄰接的棧。
    在這裏插入圖片描述
  • 例題
    設有一個雙端隊列,輸入序列爲1,2,3,4,試分別求出以下條件的輸出序列。
    (1)能由輸入受限的雙端隊列得到,但不能由輸出受限的雙端隊列得到的輸出序列。
    (2)能由輸出受限制的雙端得到,但不能由輸入受限的得到。
    (3)既不能由輸入受限的得到,也不能由輸出受限的得到。
    解答
    在這裏插入圖片描述

3.棧和隊列的應用

3.1 棧在括號匹配中的應用

  • 在算術表達式中,右括號和左括號的匹配次序正好符合後到的括號要最先被匹配的“後進先出”堆棧操作特定,因此可藉助棧來操作。遇到左括號就入棧,遇到右括號就看是否匹配,匹配的話出棧並且繼續往後進行。
    括號匹配有以下四種情況
    1.左右括號匹配次序不正確
    2.右括號多於左括號
    3.左括號多於右括號
    4.括號匹配正確

3.2 棧在表達式求值中的應用

  • 首先我們要知道表達式分爲三類:
    ①中綴表達式:a+(b-c/d)e
    ②前綴表達式+a
    -be
    ③後綴表達式abcd/-e*+
    由於運算符有優先級,所以在計算機中計算一箇中綴的表達式非常困難,特別是帶括號的更麻煩,而後綴表達式中既無運算符優先又無括號的約束問題因爲在後綴表達式中運算符出現的順序正是計算的順序,所以計算一個後綴的表達式更簡單。
    所以,可以將求算術表達式的值的過程化成兩個過程:

    • 將一箇中綴表達式化成一個後綴表達式 。
    • 對後綴表達式進行求值
  • 將中綴變爲後綴
    因爲要將運算符出現的次序與真正的算術運算順序一直, 所以,就要讓優先級高的以及括號內的運算符出現在前面,
    因此要使用一個棧來保留還未送往後綴表達式的運算符,此棧稱爲運算符棧 。

  • 算法描述如下:
    (1)初始化一個運算符棧
    (2)從算術表達式輸入的字符串中,從左到右的讀取一個字符
    (3)若當前的 字符是操作數,則直接送往後綴表達式
    (4)若當前的字符是左括號,則將其壓入運算符棧
    (5)若當前的字符是操作符,則進行如下 操作:

    • 1.當運算符棧爲空時,直接將其壓入棧。
    • 當此運算符的優先級高於棧頂的運算符時,則將此運算符壓入棧,否則,彈出棧頂運算符送往後綴式,並將當前運算符壓棧,重複步驟(5)

    (6)若當前字符是右括號,反覆將棧頂符號彈出,並送往後綴表達式中,知道棧頂元素爲左括號爲止,然後將左括號出棧並丟棄
    (7)若讀取還未結束,則重複步驟(2)
    (8)若讀取結束,則將棧中剩餘的所有的運算符彈出並送往後綴表達式。

  • 計算後綴表達式
    計算步驟很簡單,就是找到運算符,然後找前面最後出現的兩個操作數,從而構成一個最小的算術表達式進行運算,
    在計算過程中也需要利用一個棧來保留後綴表達式中還未參與運算的操作數,稱爲操作數棧,
    算法描述如下:
    (1)初始化一個操作數棧
    (2)從左到右依次讀入後綴表達式中的字符

    • 若當前字符是操作數,則壓入操作數棧。
    • 若當前字符是操作符,則從棧頂彈出兩個操作數參與運算,並將運算結果壓入操作數棧內。

    (3)重複步驟(2)直到讀入的後綴表達式結束爲止,則操作數棧中的棧頂元素即爲後綴表達式的結果

3.3 棧在遞歸中的應用

3.4 隊列在層次遍歷中的應用

3.5 隊列在計算機系統中的應用

後面再寫。

4 特殊矩陣的壓縮存儲

4.1 數組的定義

自己理解。

4.2 數組的存儲結構

  • 二維數組按行和按列存儲:
    • 按行存儲:行號小的優先存儲,以此類推。如:a00,a01,a01,a10,a11,12…
    • 按列存儲:列號小的優先,同上不在舉例。

4.3 矩陣的壓縮存儲

  • 壓縮存儲:指爲多個值相同的元素只分配一個存儲空間,對0元素不分配存儲空間。其目的是爲了節省存儲空間。
  • 特殊矩陣:指具有許多相同矩陣元素或0元素,並且這些相同矩陣元素或0元素的分佈有一定規律性的矩陣。常見的特殊矩陣有對稱矩陣、上(下)三角矩陣、對角矩陣。
    直接安利這個博客,牛皮!!!矩陣的壓縮存儲,點這裏
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章