2018年第14周-大話數據結構的筆記(棧與隊列)

棧與隊列

棧(stack)是限定僅在表尾進行插入和刪除操做的線性表git

容許插入和刪除的一端稱爲棧頂(top),另外一端稱爲棧底(bottom),不含任何數據元素的棧稱爲空棧。棧又稱爲後進先出(Last In First Out)的線性表,簡稱LIFO結構。大話數據結構的程傑老師用「彈夾式手槍和左輪手槍」這個例子來比喻,很形象。

棧的插入操做,叫作進棧,也稱壓棧入棧
棧的刪除操做,叫作出棧,也稱彈棧數組

棧的抽象數據類型

對於棧來說,理論上線性表的操做特性它都具有,可因爲它的特殊性,因此針對它的操做上會有變化。特別是插入和刪除操做,咱們更名爲push和pop。這對於Java的面向對象來講可能體會比較深,如ArrayList和Vector都是繼承抽象類AbstractList,而Vector又是Stack的父類,因此Stack是具備普通線性表的功能,但又具備本身push和pop的方法。。數據結構

ADT 棧(stack)  
Data
    同線性表。元素具備相同的類型,相鄰元素具備前驅和後繼關係。

Operation
    InitStack(*S);        //初始化操做,創建一個空棧S
    DestroyStack(*S);    //若棧存在,則銷燬它  
    ClearStack(*S);        //將棧清空
    StackEmpty(S);        //若棧爲空,返回true,不然返回false
    GetTop(S,*e);        //若棧存在且非空,用e返回S的棧頂元素
    Push(*S,e);            //若棧S存在,插入新元素e到棧S中並稱爲棧頂元素  
    Pop(*S,*e);            //刪除棧S中棧頂元素,並用e返回其值  
    StackLength(S);        //返回棧S的元素個數
endADT

逆波蘭表達式(Reverse Polish Notation, RPN)又稱後綴表達式。是由波蘭邏輯學家J.Lukasiewicz於1929年提出了另外一種表示表達式的方法,按此方法,每一運算符都置於其運算對象以後,故稱爲後綴表示。app

與後綴表達式對應的是中綴表達式,也就是咱們經常使用的9+(3-1)x3+10/2這種表達式,中綴表達式是二元運算符置於與之相關的兩個運算對象之間。

後綴表達式的計算規則:
規則:從左到右遍歷表達式的每一個數字和符號,遇到是數字就進棧,遇到符號就將處於棧頂兩個數字出棧,進行運算,運算結果進棧,一直到最終結果。反正運算符是不會進棧的。
舉個栗子,如9 3 1 - 3 * + 10 2 / +步驟以下:code

  1. 初始化一個空棧,此棧用來對要運算的數字(操做數)進出使用;
  2. 後綴表達式的前三個都是數字,因此九、3 、1進棧;
  3. 接下來是減號-,因此將棧中的操做數1和操做數3出棧,操做數1做爲減數,操做數3做爲被減數。則就是3-1=2,而後再將2進棧;
  4. 接着是數字3進棧;
  5. 後面是乘號,也就是把操做數3和操做數2出棧,23=6,而後將6進棧;
  6. 接下來是加號+,因此把操做數6和9出棧,9+6=15,將15進棧;
  7. 接着是10與2兩數字進棧;
  8. 後面是除號/,所以,棧頂的2與10出棧,10/2=5,將5進棧;
  9. 最後一個符號是加號+,因此將15和5出棧並相加,15+5=20,將20進棧;
  10. 遍歷完畢,20出棧,棧變爲空,20就是最終結果。

中綴表達式轉後綴表達式(計算器實現原理):對象

規則是:從左到右遍歷中綴表達式的每一個數字和符號,如果數字就輸出,即爲後綴表達式的一部分;若是是符號,則判斷此符號與棧頂符號的優先級,若是棧頂元素是右括號或棧頂元素的優先級高於或等於棧頂符號(乘除優先加減),則棧頂元素依次出棧並輸出,並將當前符號進棧,一直到最終輸出後綴表達式位置。反正數字(操做數)和括號是不會進棧的。
舉個栗子,將中綴表達式9+(3-1)x3+10/2轉爲後綴表達式9 3 1 - 3 * + 10 2 / + 步驟以下:繼承

  1. 初始化一個空棧,用於對符號(操做符)進出棧使用;
  2. 第一個字符是數字9,輸出9,後面是符號加號+,加號+進棧;
  3. 第三個字符是左括號「(」,依然是符號,因其只是左括號,還未匹配,故進棧;
  4. 第四個字符是數字3,輸出3,總表達式爲 9 3,接着是減號-,進棧;
  5. 接下來是數字1,輸出1,總表達式爲 9 3 1,後面符號是右括號「)」,此時,咱們須要去匹配以前的左括號「(」,因此棧頂依次出棧,並輸出,直到左括號「(」出棧爲止。此時左括號上方只有減號-,所以輸出減號-。此時表達式爲 9 3 1 -;
  6. 接着是字符是乘號×,因爲乘號優先級高於棧頂元素(此時是加號+),此時將乘號×入棧。
  7. 接着字符是數字3,輸出3,此時表達式爲9 3 1 - 3;
  8. 跟着是字符是加號+,因爲加號+優先級低於棧頂元素(此時是乘號×),因此棧中元素出棧並輸出直到沒有比當前字符優先級更低的符號,也就是輸出乘號×和加號+,而後當前元素加號+則進棧,此時表達式爲 9 3 1 - 3 * +;
  9. 接着字符是數字10,輸出10,此時表達式爲 9 3 1 - 3 * + 10;
  10. 接着是字符除號/,因爲棧頂元素如今是加號,優先級低於除號/,因此除號/入棧;
  11. 接着是數字2,輸出數字2,此時表達式爲 9 3 1 - 3 * + 10 2;
  12. 遍歷完畢,將棧內元素出棧,分別是除號/和加號+,此時表達式爲 9 3 1 - 3 * + 10 2 / +爲最終結果。

總結下:
將中綴表達式轉化爲後綴表達式(數字(操做數)和括號是不會進棧的);
將後綴表達式進行運算得出結果(運算符是不會進棧的);隊列

隊列

隊列(queue)是隻容許在一端進行插入操做,而在另一端進行刪除操做的線性表
再次提起下,以增強記憶,既然時線性表,就說明能夠用數組或鏈表的物理結構進行存儲。get

隊列是一種先進先出(First In First Out)的線性表,簡稱FIFO。容許插入的一端稱爲堆尾,容許刪除的一端稱爲隊頭。

隊列的抽象數據類型

一樣是線性表,隊列也有相似線性表的各類操做,不一樣的就是插入數據只能在隊尾進行,刪除數據只能在隊頭進行。it

ADT 隊列(Queue)
Data
    同線性表。元素具備相同的類型,相鄰元素具備前驅和後繼關係。

Operation
    InitQueue(*Q);        //初始化操做,創建一個空隊列Q
    DestroyQueue(*Q);     //若隊列Q存在,則銷燬它
    ClearQueue(*Q);        //將隊列Q清空
    QueueEmpty(Q);        //若隊列Q爲空,返回true,不然返回false    
    GetHead(Q,*e);        //若隊列Q存在且非空,用e返回隊列Q的隊頭元素
    EnQueue(*Q,e);        //若隊列Q存在,插入新元素e到隊列Q中併成爲隊尾元素
    Dequeue(*Q,*e);        //刪除隊列Q中隊頭元素,並用e返回其值
    QueueLength(Q);        //返回隊列Q的元素個數

循環隊列:把隊列的頭尾相接的順序存儲結構

總結

使用了棧和隊列結合起來,能夠寫出一個簡單的計算器,我用C寫了一個,感興趣能夠點擊下

參考:《大話數據結構》

相關文章
相關標籤/搜索