前言:通常我們會遇到一些問題,采用一些標准的數據結構,如雙鏈表、散列表或二叉查找數時,不能夠滿足操作要求,需要對這些數據結構進行擴張,添加一些額外的信息使得能夠完成新的操作。附加的信息需要對數據結構的某些操作進行調整,這個是非常關鍵的步驟,決定着數據結構擴張是否能夠實現。本章主要討論了紅黑樹結構的擴張,介紹了兩種擴張方式。第一種方式擴張使得紅黑色能夠支持動態集合上順序統計,快速找出集合中第i小的數,或給出某個元素在集合的全序中的排名。第二種方式擴張使得紅黑色能夠進行區間操作,可以很快地找到集合中覆蓋的區間。關於紅黑色請參考第13章,http://www.cnblogs.com/Anker/archive/2013/01/30/2882773.html。
1、動態順序統計
在第九章介紹了順序統計的概念,大概的意思是在包含有n個元素的集合中,第i個順序統計量指的是該集合中第i小的元素。在一個無序的集合中,任意順序統計量都可以在O(n)時間內找到,詳細情況可以參考http://www.cnblogs.com/Anker/archive/2013/01/25/2877311.html。書中在此基礎上修改紅黑樹的結構,使得任意的順序統計量都可以再O(lgn)時間內確定。向紅黑樹的結構中添加一個size域,表示包含自身節點的當前節點的子樹節點的數目。這樣修改后可以快速支持順序統計量操作,將這種修改后的紅黑樹叫做:順序統計量樹T。修改后的結構如下所示:
1 struct RBTreeNode 2 { 3 int key; 4 int color; 5 struct RBTreeNode *parent; 6 struct RBTreeNode *left; 7 struct RBTreeNode *right; 8 int size; 9 };
例如給定紅黑樹的一個節點x,則size[x] = size[left[x]]+size[right[x]]+1。size[x]為包含以x為根的子樹的節點數(包含x本身),即子樹的大小。如果哨兵定義為0,即設置size[nil[T]]=0。
下面給出一個修改后的紅黑樹的例子,如下圖所示:
紅黑樹是二叉排序樹,按照中序遍歷從小到大輸出紅黑樹中的關鍵字。從圖中可以看出,添加size域后,很方便看出每個節點的子樹的節點數目(包含自身節點)。書中在后面討論這種結構的操作,分別討論如下:
(1)檢索具有給定排序的元素
過程OS_SELECT(x,i)返回一個指向以x為根的子樹中包含第小關鍵字的結點的指針,即為了找出順序統計量樹T中的第i小關鍵字,可以調用OS_SELECT(root[T],i)。書中給出了偽代碼如下:
1 OS_SELECT(x,i) 2 r = size[left[x]]+1; //先計算x的處於的位置 3 if i = r //x正好是第i小的關鍵字 4 then return x; 5 else if i < r //x比第i關鍵字大,則在其左子樹查找 6 then return OS_SELECT(left[x],i) 7 else return OS_SELECT(right[x],i-r) //x比第i關鍵字小,則在其右子樹查找
該過程類似二分查找,每一次遞歸調用都在順序統計數中下降一層,故最壞情況下OS_SELECT的總時間與樹的高度成正比,紅黑樹的高度為lgn。故OS_SELECT的運行時間為:O(lgn)。
(2)確定一個元素的秩(位置)
給定指向一順序統計樹T中節點x的指針,求x在順序統計樹中序遍歷得到的線性序中的位置。書中給出了OS_RANK(T,x)過程的偽代碼:
1 OS_RANK(T,x) 2 r = size[left[x]]+1; //獲取以x為根子樹中x的位置(中序遍歷) 3 y = x; 4 while y != root[T] //從下向上直到根節點 5 do if y = right[p[y]] //如果是右子樹 6 then r = r + size[left[p[y]]]+1; 7 y = p[y]; //向上移動 8 return r;
從程序總可以看出當y == root[T]時候循環終止,此時以y為根的子樹是課完整樹,此時r值是這顆整樹中key[x]的秩。while循環中的每一次迭代花O(1)時間,且y在每次迭代中沿樹上升一層,故在最壞情況下0S_RANK的運行時間與樹的高度成正比:對含n個節點的順序統計樹時間為O(lgn)。
(3)對子樹規模的維護
在紅黑樹中添加size域后,能夠通過OS_SELECT和OS_RANK迅速計算出所需的順序統信息。通過修改紅黑樹的插入和刪除操作,在此過程是通過旋轉來修改size域。關於這部分需要在紅黑樹的基礎上進行改進,比較復雜,暫時沒有實現。
2、如何擴張數據結構
對一種數據結構的擴張過程分為四個步驟:
1)選擇基礎數據結構
2)確定要在基礎數據結構中添加哪些信息
3)驗證可用基礎數據結構上的基本修改操作來維護這些新添加的信息
4)設計新的操作
書中給出了對紅黑樹進行擴張的定理,並給出了證明,這個看的時候有些難度,暫時跳過了。大概意思就是說當紅黑樹被選作基礎數據結構時,某些類型的附加信息總是可以用插入和刪除來進行有效地維護。
3、區間樹
這小結講的是擴張紅黑樹以支持由區間構成的動態集合上的操作。區間可以很方便的表示各占用一段連續時間的一些事情。區間樹是一種動態集合進行維護的紅黑樹,該集合中的每個元素x都包含在一個區間int[x]。區間樹支持下列操作:
INTERVAL_INSERT(T,x):將包含區間域int的元素x插入到區間樹T中
INTERVAL_DELETE(T,X):從區間樹T中刪除元素x
INTERVAL_SEARCH(T,i):返回一個指向區間樹T中元素x的指針,使int[x]與i重疊,若集合中無此元素存在,則返回nil[T]。
修改紅黑樹得到的區間樹如下圖所示:
從圖可以看出,對區間樹以每個節點的左端點值進行中序變量即可得到有序的序列。有了區間樹的結果就很容易實現其相關操作。
4、總結
本章主要是介紹一種數據結構擴張的方法,靈活性非常之大。以紅黑樹作為例子,我是在年前看的紅黑樹,並給以實現。年后了,對紅黑樹忘了差不多了。呵呵,真是一天不學習,趕不上啦。本章看完比較郁悶,沒有去實現。實現的難度非常具有挑戰性,何時能夠實現,我心里有些忐忑。肯定不會放棄,一定會找個時間把這些實現一下。