啓示:
-
棧與隊列
棧是限定僅在表尾進行插入和刪除操做的線性表
隊列是隻容許在一端進行插入操做,而在另外一端進行刪除操做的線性表
目錄
<!-- GFM-TOC -->html
<!-- GFM-TOC -->java
========================================git
4.1 開場白
- 一些能夠略過的場面話...
- 以左輪手槍和彈夾式手槍的區別引入
========================================github
4.2 棧的定義
-
棧的引入:
-
棧的常見應用:
軟件中的撤銷(undo)操做,瀏覽器歷史紀錄,Android中的最近任務,Activity的啓動模式,CPU中棧的實現,Word自動保存,解析計算式,解析xml/json
-
定義:棧(stack)是限定僅在表尾進行插入和刪除操做的線性表
-
棧首先是一個線性表,棧元素具備線性關係,即前驅後繼關係。
-
棧頂(top):容許插入和刪除的一端稱爲棧頂
-
棧底(bottom):另外一端稱爲棧底
-
定義所述「表尾插入刪除」,表尾指的是棧頂,而不是棧底
-
特殊的線性表:特殊在於限制了插入刪除的位置,始終在棧頂進行,棧底是固定的
-
空棧:不含任何數據元素的棧稱爲空棧
-
LIFO:last in first out,棧又稱爲後進先出的線性表,簡稱LIFO結構
-
棧的插入操做:進棧,也稱壓棧、入棧
-
棧的刪除操做:出棧,也稱彈棧
-
進棧出棧變化形式
-
舉例來講,三個int型數字元素1,2,3依次進棧,出棧次序有5種
- 321:123進,321出
- 123:1進1出,2進2出,3進3出
- 213:12進,21出,3進3出
- 132:1進1出,23進,32出
- 231:12進,2出,3進,31出
-
求出棧序列個數:卡特蘭數公式:C(2n,n)/(n+1)
- ### 其中,卡特蘭數前幾項爲: 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796json
-
棧的應用之n階漢諾塔盤問題(Hanoi)
-
規則:
-
在遊戲中,總共有n個金屬盤片的塔叫作n階漢諾塔

(沒搞懂原理,也沒搞懂代碼,可是先把結論記下來)c#
========================================數組
4.3 棧的抽象數據類型
-
棧做爲線性表,理論上線性表的操做特性都具有
-
針對特殊性,插入和刪除更名爲push和pop,即壓和彈

========================================瀏覽器
4.4 棧的順序存儲結構及實現
-
一、棧的順序存儲結構
-
棧的順序存儲也是線性表順序存儲的簡化,簡稱爲順序棧
-
數組中,用下標爲0的一端做爲棧底,由於首元素都存在棧底,變化小
-
棧頂top:若存儲棧長度爲StackSize,則top必須小於StackSize
-
空棧:棧中有一個元素時top=0,以示區別,空棧的斷定條件設爲top=-1
-
棧的結構定義:





-
時間複雜度:
-
進棧、出棧不涉及任何循環語句,時間複雜度均爲O(1)
========================================數據結構
4.5 兩棧共享空間
-
兩棧共享空間的關鍵思路:
-
兩個棧底分別位於數組的始端(下標0)和數組的末端(下標數組長度n-1),增長元素即從兩端點向中間延伸
-
兩棧共享空間的前提:
-
兩棧共享空間的圖示:

-
棧滿:
-
通常狀況:兩個棧見面之時,即兩個指針相差1,top1+1==top2時
-
極端狀況:2空時,top1=n-1,則1滿;1空,top2=0,則2滿
-
兩棧共享空間的結構代碼:

-
兩棧共享空間的push方法代碼實現:
除了要插入元素值參數,還須要一個判斷是棧1仍是2的棧號參數stackNumber

-
兩棧共享空間的pop方法代碼實現:
參數僅爲判斷棧1或2的參數stackNumber

========================================函數
4.6 棧的鏈式存儲結構及實現
-
棧的鏈式存儲結構
-
棧的鏈式存儲結構,簡稱鏈棧
-
棧頂放在單鏈表的頭部,且不須要頭結點
-
空棧:鏈表原定義爲頭指針指向空,故鏈棧的空是top=NULL
-
圖示:


-
鏈棧的操做大部分與單鏈表相似,只是插入、刪除特殊
-
棧的鏈式存儲結構--進棧操做




-
時間複雜度:
-
鏈棧的push和pop均不涉及循環操做,時間複雜度爲O(1)
========================================
4.7 棧的做用
-
類比明明能夠靠腳走到世界上任何地方,爲何還要乘坐飛機火車呢
-
棧的引入簡化了程序涉及的問題,劃分了不一樣關注層次,使思考範圍縮小,更加聚焦於問題核心
(好比像數組之類的,要分散精力去考慮數組的下標增減等細節問題。。)
-
如今許多高級語言如java,c#等,都有對棧結構的封裝,不用關心實現細節,直接使用Stack的push和pop方法,很是方便
========================================
4.8 棧的應用--遞歸



-
遞歸定義
-
把一個直接調用本身或者經過一系列的調用語句間接地調用本身的函數,稱爲遞歸函數。
-
每一個遞歸定義必須至少有一個條件,知足時遞歸再也不進行,即再也不引用自身而是返回值退出。
-
迭代和遞歸的區別:
- 迭代使用循環結構,遞歸使用選擇結構
- 遞歸使程序的結構更清晰、更簡潔
- 遞歸調用會創建函數的副本,會耗費大量的時間和內存
-
遞歸與棧結構:
- 遞歸過程退回的順序是它前進順序的逆序。在退回過程當中,可能要執行某些動做,包括恢復在前進過程當中存儲起來的某些數據。
- 這種存儲某些數據,並在後面又以存儲的逆序恢復這些數據,以提供以後使用的需求,這顯然很符合棧這樣的數據結構。
========================================
4.9 棧的應用--四則運算表達式求值
-
後綴(逆波蘭)表示法定義
-
一種不須要括號的後綴表達法,也稱爲逆波蘭(Reverse Polish Notation, RPN)
-
後綴: 全部的符號都是要在運算數字的後面出現的。
-
沒了括號,機器能夠更好地執行。
-
中綴表達式
-
定義:經常使用的標準四則運算表達式,全部的運算符號都在兩數字的中間
-
想要讓計算機處理常見的中綴表達式,最重要的有兩步:
-
一、將中綴表達式轉化爲後綴表達式(棧用來進出運算的符號)
-
二、將後綴表達式進行運算得出結果(棧用來進出運算的數字)
-
中綴表達式轉後綴表達式(數字所有輸出,只有符號進棧出棧)
-
規則:
-
從左到右遍歷中綴表達式的每一個數字和符號
-
如果數字就輸出,即成爲後綴表達式的一部分
-
如果符號,先判斷其與棧頂符號的優先級
-
是右括號或優先級低於棧頂符號,則棧頂元素依次出棧並輸出,並將當前符號進棧
-
若優先級高於棧頂符號,則不用管棧頂,直接壓棧
-
一直到最終輸出後綴表達式爲止
-
圖示:
- ### 注:右括號不進棧,當匹配到左括號時,直接到左括號的部分出棧
-
後綴表達式計算結果(只有數字進棧出棧)
-
規則:
-
從左到右遍歷表達式的每一個數字和符號
-
遇到數字就進棧
-
遇到符號,就將處於棧頂的兩個數字出棧,並運算,且運算結果進棧
-
一直到最終得到結果
-
圖示:
- ### 注:遇運算符取出兩數計算,而後須要結果再次進棧,最終結果會出如今棧裏
-
示例:
-
中綴表達式:9 + ( 3 - 1 ) * 3 +10 / 2
-
後綴表達式:9 3 1 - 3 * + 10 2 / +
========================================
4.10 隊列的定義
-
隊列的引入:
-
常見應用:電腦卡殼時,過一下子又自顧自地按順序把以前的操做執行一遍;客服排隊;鍵盤輸入到顯示器輸出等,都是隊列
-
定義:隊列(queue)-- 只容許在一端進行插入操做,而在另外一端進行刪除操做的線性表
-
容許插入的一端稱爲隊尾,容許刪除的一端稱爲隊頭
(先進先出,所以頭做爲先進的,會先出,所以刪除端是隊頭)
-
FIFO:first in first out,先進先出的線性表
-
圖示:設q = (a1, a2, ... , an)

========================================
4.11 隊列的抽象數據類型
-
隊列一樣是線性表,也有相似線性表的各類操做
-
不一樣在於:插入只能在隊尾,刪除只能在隊頭

========================================
4.12 循環隊列
-
注:棧和隊列做爲特殊的線性表,一樣都具備順序存儲和鏈式存儲兩種存儲方式。
-
隊列順序存儲的不足
-
當隊頭固定設爲數組下標爲0的位置時:入隊O(1),但出隊O(n)

-
當不限制隊頭必須在數組下標爲0的位置時,能夠提升一些性能

-
引入兩個指針:front指向隊頭,rear指向隊尾的下一個位置
當空隊列:front=rear


-
循環隊列定義
-
定義:隊列的頭尾相接的順序存儲結構稱爲循環隊列。
-
從新定義隊列的空和滿
-
QueueSize:隊列的最大尺寸
-
隊列空: front == rear
-
隊列滿: front == (rear + 1) % QueueSize
(修改隊列滿的條件,保留一個元素空間)

-
計算隊列長度的公式:(rear - front + QueueSize) % QueueSize
-
循環隊列的代碼實現





-
循環隊列的相關條件和公式:
-
1.隊空條件:rear==front
-
2.隊滿條件:(rear+1) %QueueSIze==front,其中QueueSize爲循環隊列的最大長度
-
3.計算隊列長度:(rear-front+QueueSize)%QueueSize
-
4.入隊:rear = (rear+1)%QueueSize
-
5.出隊:front = (front+1)%QueueSize
========================================
4.13 隊列的鏈式存儲結構及實現
-
定義:
-
隊列的鏈式存儲結構,其實就是線性表的單鏈表,但只能尾進頭出,簡稱鏈隊列。
-
圖示:





-
隊列的鏈式存儲結構--出隊
-
出隊,即頭結點的後繼結點出隊,將頭結點的後繼改成它後面的結點
-
若鏈表除頭結點外,只剩一個元素,則需將rear指向頭結點
-
圖示:


-
時間空間複雜度分析 -- 循環隊列和鏈隊列對比
-
時間上:都是O(1)
-
空間上:
-
循環隊列:事先申請好空間,使用期間不釋放
-
鏈隊列:每次申請和釋放結點也會存在一些時間開銷
-
循環隊列:固定長度,故存在存儲元素個數和空間浪費的問題
-
鏈隊列:須要指針域,產生一些空間上的開銷,在空間上更靈活
========================================
4.14 總結回顧

========================================
4.15 結尾語
END