http://www.cnblogs.com/sungoshawk/p/3649004.html
算法導論讀書筆記(10)
棧和隊列
棧和隊列都是動態集合。棧實現了一種 先進先出 的策略。類似地,隊列實現了一種 後進先出 的策略。
棧
作用於棧上的 INSERT
操作稱爲 壓入 ( PUSH
),而無參的 DELETE
操作常稱爲 彈出 ( POP
)。可以使用一個數組 S [ 1 .. n ]來實現一個至多有 n 個元素的棧。如下圖所示,數組 S 有個屬性 S.top ,它指向最近插入的元素。
STACK-EMPTY(S) 1 if S.top == 0 2 return TRUE 3 else 4 return FALSE
PUSH(S, x) 1 S.top = S.top + 1 2 S[S.top] = x
POP(S) 1 if STACK-EMPTY(S) 2 error "underflow" 3 else 4 S.top = S.top - 1 5 return S[S.top + 1]
隊列
我們把作用於隊列上的 INSERT
操作稱爲 入隊 ( ENQUEUE
),把作用於隊列上的 DELETE
操作稱爲 出隊 ( DEQUEUE
)。隊列有 頭 和 尾 。當一個元素入隊時,將排在隊尾,而出隊的元素總是隊首元素。下圖說明了用一個數組 Q [
1 .. n ]來實現一個至多含 n - 1 個元素的隊列的方法。隊列具有屬性 Q.head ,它指向隊列的頭,另一個屬性爲 Q.tail ,它指向新元素將會被插入的地方。
ENQUEUE(Q, x) 1 Q[Q.tail] = x 2 if Q.tail == Q.length 3 Q.tail = 1 4 else 5 Q.tail = Q.tail + 1
DEQUEUE(Q) 1 x = Q[Q.head] 2 if Q.head == Q.length 3 Q.head = 1 4 else 5 Q.head = Q.head + 1 6 return x
鏈表
在 鏈表 中,各對象按線性順序排序。其順序由各對象中的指針決定。本節介紹的是無序的雙鏈表。 雙鏈表 的每一個元素都是一個對象,每個對象包含一個關鍵字域和兩個指針域: next 和 prev 。對鏈表中的某個元素 x , x.next 指向鏈表中 x 的後繼元素,而 x.prev 則指向鏈表中 x 的前驅元素。下面給出的是鏈表的基本操作。
LIST-SEARCH(L, k) 1 x = L.head 2 while x != NIL and x.key != k 3 x = x.next 4 return x
LIST-INSERT(L, x) 1 x.next = L.head 2 if L.head != NIL 3 L.head.prev = x 4 L.head = x 5 x.prev = NIL
LIST-DELETE(L, x) 1 if x.prev != NIL 2 x.prev.next = x.next 3 else 4 L.head = x.next 5 if x.next != NIL 6 x.next.prev = x.prev
有根樹的表示
用鏈表表示有根樹
二叉樹
如下圖所示,用域 p , left , right 來存放指向二叉樹 T 中的父親,左兒子和右兒子的指針。如果 x.p = NIL
,則 x 爲根。如果結點 x 無左兒子,則 x.left =NIL
,對右兒子也類似。整個樹 T 的根由屬性 T.root 指向。如果 T.root = NIL
,則樹爲空。
分支數無限的有根樹
可以用二叉樹很方便地表示具有任意子女數的樹。該方法的優點是對任意含 n 個結點的有根樹僅用 O ( n )空間。這種 左孩子 , 右兄弟 的表示如下圖所示。每個結點都包含一個父親指針 p , T.root 指向樹 T 的根。每個結點 x 不再包含指向每個孩子結點的指針,而僅包含兩個指針:
- x.left-child 指向結點 x 的最左孩子。
- x.right-sibling 指向結點 x 緊右邊的兄弟。
如果 x 沒有孩子,則 x.left-child = NIL
;如果 x 是其父結點的最右孩子,則 x.right-sibling = NIL
。