引言 數據結構
集合:如同在數學中一樣,集合也是計算機科學的基礎。不過數學上的集合時不變的,而算法所操作的集合是動態改變的。數據結構這一部分介紹在計算機中表示和操作有窮動態集合的一些基本技術。
字典:許多算法要求能夠將元素插入集合,從集合中刪除元素,以及測試元素是否屬於集合。支持這些操作的動態集合就叫字典。另一些算法可能需要更復雜的操作,實現動態集合的最好方案取決於要支持什麼樣的集合操作。
動態集合上的操作:下面給出一些典型的操作
SEARCH(S,k) : 在集合S中查找關鍵字值爲k的元素x;或者當不存在這樣的元素時返回NIL。
INSERT(S,x):將元素添加到S中去。
DELETE(S,x):將x從S中刪除,注意參數是元素x的指針而不是關鍵字k。
MINUM(S):查詢返回S中具有最小關鍵字的元素。
MAXIMUM(S):查詢返回S中具有最大關鍵字的元素。
SUCCESSOR(S,x):查詢,S中元素x的後繼元素,當不存在時返回NIL。
PREDECESSOR(S,x):查詢S中元素x的前繼元素,當不存在時返回NIL。
第十章:基本數據結構
10.1棧和隊列
棧和隊列都是動態集合,可以用DELETE操作去掉的元素時預先規定好的。在棧中,可以去掉元素是最近插入的哪一個:棧實現了一種後進先出的策略;在隊列中,可以去掉的元素總是在集合中存在時間最長的那一個:隊列實現了先進先出的策略。
棧
棧上的INSERT操作稱爲壓棧(PUSH),無參數的DELETE操作稱爲彈出(POP)。可以用數組S[1...n]來實現一個至多n個元素的棧,屬性top[S],指向最近插入的元素。S[1]是棧底元素,S[top[S]]是棧頂元素。當top[s]=0時,棧中不包含任何元素。
STACK-EMPTY(S)
1 if top[S]=0
2 then return TRUE
3 else return FALSE
PUSH(S, x)
1 top[S] <-- top[S]+1
2 S[top[S]] <-- x
POP(S)
1 if STACK-EMPTY(S)
2 then error "underflow"
3 else top[S]<--top[S]-1
4 return S[top[s]+1]
隊列
隊列上插入操作稱爲入隊列ENQUEUE,刪除操作稱出隊列DEQUEUE。可以用數組Q[1...n]來實現隊列,屬性head[Q]指向隊列的頭,屬性tail[Q],它指向新元素將會插入的地方。當head[Q]=tail[Q]時,隊列爲空。當head[Q]=tail[Q]+1隊列滿。
ENQUEUE(Q,x)
1 Q[tail[Q]]<--x
2 if tail[Q]=length[Q]
3 then tail[Q]<--1
4 else tail[Q]<--tail[Q]+1
DEQUEUE(Q)
1 x<--Q[head[Q]]
2 if head[Q]=length[Q]
3 then head[Q]<--1
4 else head[Q]<head[Q]+1
5 return x
10.2鏈表
雙鏈表L的每個元素都是對象,每個對象包含一個關鍵字域和兩個指針域:next和prev。next[x]指向鏈表中x的後繼元素,而prev[x]則指向x的前驅元素。如果prev[x]=NIL則x是鏈表的第一個元素,如果next[x]=NIL,則元素x是最後一個元素。屬性head[L]指向鏈表的第一個元素。
LIST-SEARCH(L,k)
1 x <-- head[L]
2 while x!=NIL and key[x]!=k
3 do x = next[x]
4 return x
LIST-INSERT(L,x)
1 next[x] = head[L]
2 if head[L]!=NIL
3 then prev[head[L]]<--x
4 head[L] = x
5 prev[x]<--NIL
LIST-DELETE(L,x)
1 if prev[x] != NIL
2 then next[prev[x]] <-- next[x]
3 else head[L] <-- next[x]
4 if next[x]!=NIL
5 then prev[next[x]]<--prev[x]
哨兵:
可以通過引入哨兵元素來簡化上面的代碼,哨兵就是個啞元對象。假設L頭部永遠有個nil[L]元素,L就永遠不會爲空。
10.4有根數的表示
鏈表的表示方法可以推廣至任意同構的數據結構上。這一節討論用鏈節數據結構表示有根樹的問題。
二叉樹
用域p、left和right來存放指向二叉樹T中的父親、左兒子和右兒子的指針。如果P[x]=NIL,則x爲根。如果left[x]=NIL,x無左兒子,右兒子也類似。整個樹T的根由屬性root[T]指向,如果root[T]=NIL,則樹爲空。
分支數無限制的有根樹
二叉樹的方法可以推廣至每個結點的子女數至多爲常數k任意種類的樹:用child1,child2...,childk來取代left和right域。如果結點的子女數是沒有限制的,這種方法就不合適了。
可以用二叉樹很方便地表示具有任意子女數的樹。每個結點有的left和right域分別替換成left-child和right-sibling,前者指向x的最左孩子,後者指向結點x緊右邊的兄弟。(左孩子,右兄弟)