算法导论第十二章:二叉查找树
查找樹(shù)是一種數(shù)據(jù)結(jié)構(gòu),它支持多種動(dòng)態(tài)集合操作,包括search, minimum, maximum, predecessor, successor, insert以及delete。他既可以用作字典,也可以用作優(yōu)先隊(duì)列。
二叉查找樹(shù)上基本操作的執(zhí)行時(shí)間和樹(shù)的高度成正比。對(duì)一棵n個(gè)結(jié)點(diǎn)的完全二叉樹(shù)來(lái)說(shuō),這些操作的最壞情況運(yùn)行時(shí)間為Θ(lgn)。但是如果樹(shù)是含有那個(gè)結(jié)點(diǎn)的線(xiàn)性鏈,則這些操作的最壞運(yùn)行時(shí)間是Θ(n)。本章可以看到一棵隨機(jī)構(gòu)造的二叉查找樹(shù)的期望高度為O(lgn)。
實(shí)際中,并不能總是保證二叉查找樹(shù)是隨機(jī)構(gòu)造的,但有些二叉查找樹(shù)的變形能保證各種基本操作的最壞情況性能。第十三章介紹的紅黑樹(shù),其高度為O(lgn)。第十八章介紹B樹(shù),這種結(jié)構(gòu)對(duì)維護(hù)隨機(jī)訪(fǎng)問(wèn)的二級(jí)存儲(chǔ)器上的數(shù)據(jù)庫(kù)特別有效。
?
二叉查找樹(shù)
? 二叉查找樹(shù)是按二叉樹(shù)結(jié)構(gòu)來(lái)組織的,每個(gè)結(jié)點(diǎn)除了key域和衛(wèi)星數(shù)據(jù)外,還包含left,right和p。結(jié)點(diǎn)的存儲(chǔ)方案滿(mǎn)足以下性質(zhì):如果結(jié)點(diǎn)y是結(jié)點(diǎn)x左子樹(shù)種的一個(gè)結(jié)點(diǎn),則key[y]<=key[x]。如果y是x右子樹(shù)中的一個(gè)結(jié)點(diǎn),則key[x]<=key[y]。
?
對(duì)二叉查找樹(shù)進(jìn)行中序遍歷可以有序輸出所有的結(jié)點(diǎn)關(guān)鍵字。
?
練習(xí):
12.1.3給出二叉樹(shù)的一個(gè)非遞歸的中序遍歷算法。
(1)可以用一個(gè)棧數(shù)據(jù)結(jié)構(gòu)來(lái)模擬遞歸過(guò)程中的棧變化過(guò)程,從而完成非遞歸形式的遍歷算法;
(2)也可以不借助棧數(shù)據(jù)結(jié)構(gòu),中序遍歷的過(guò)程中是由從根到葉、從父到子的down過(guò)和從子到父的up過(guò)程組成的。在非遞歸的情況下,在處理某個(gè)節(jié)點(diǎn)x時(shí),關(guān)鍵是要分清下一步是要down還是up。其實(shí)這可以由上一個(gè)結(jié)點(diǎn)位置來(lái)判斷,如果上一個(gè)結(jié)點(diǎn)是x的父節(jié)點(diǎn)且x是它的左兒子,則應(yīng)該往左down,如果x是它的右兒子,則應(yīng)該up。如果上一結(jié)點(diǎn)是x的左兒子,則應(yīng)該往右down,如果是x的右兒子,則應(yīng)該up。
OPTYPE {down, up}
INORDER_WITHOUTSTACK(T)
1???????? Node x = root[T]
2???????? Node last_node = nil
3???????? OPTYPE last_op = down
4???????? while (!over)
5???????? ??switch (last_op)
6???????? ????Case down:???????
7???????? ???????If (left[x]) last_node=x, last_op=down, x=left[x]
8???????? ???????Else output(x);
9???????? ???????????if (right[x]) last_node=x, last_op=down, x=right[x]
10???? ???????????Else if (x.p) last_node=x,last_op=up,x=x.p
11???? ???????????????Else over=true
12???? ????Case up:
13???? ???????If (last_node = left[x]) output(x)
14???? ??????????????????????????If (right[x]) last_node=x, last_op=down, x=right[x]
15???? ????????????????????????Else if (x.p) last_node=x,last_op=up,x=x.p
16???? ????????????????????????????Else over=true
17???? ?????Else if (x.p) last_node=x,last_op=up,x=x.p
18???? ????????????????????????????Else over=true?
?
查詢(xún)二叉查找樹(shù)
查找關(guān)鍵字k:
從樹(shù)根開(kāi)始比較key[x]和k,如果key[x]=k停止,如果key[x]>k則往左子樹(shù)查找,否則往右子樹(shù)查找,如此循環(huán)。
?
最大關(guān)鍵字元素和最小關(guān)鍵字元素:
最大關(guān)鍵字就是樹(shù)的最右結(jié)點(diǎn):沿樹(shù)根往右子節(jié)點(diǎn)移動(dòng),直到NIL。
最小關(guān)鍵字元素就是樹(shù)的最左結(jié)點(diǎn):沿樹(shù)根往左子結(jié)點(diǎn)移動(dòng),直到NIL。
?
前驅(qū)和后繼:
某個(gè)節(jié)點(diǎn)x的前驅(qū):如果x有左子,那么前驅(qū)是左子樹(shù)的最大關(guān)鍵字;否則從下往上查看x的祖先結(jié)點(diǎn),直到某個(gè)節(jié)點(diǎn)y滿(mǎn)足性質(zhì):x出現(xiàn)在y的右子樹(shù)種。如果y存在,則y就是x的前驅(qū),否則x沒(méi)有前驅(qū)。
某個(gè)節(jié)點(diǎn)x的后繼:如果x有右子,則x的后繼是右子樹(shù)的最小關(guān)鍵字;否則從下往上查看x的祖先結(jié)點(diǎn),直到某個(gè)結(jié)點(diǎn)y滿(mǎn)足性質(zhì):x出現(xiàn)在y的左字?jǐn)?shù)中,如果y存在,則y是x的后繼,否則x沒(méi)有后繼。
?
查找前驅(qū)和后繼的最壞運(yùn)行時(shí)間為lgn。
但對(duì)x查找其后繼(前驅(qū))的k個(gè)結(jié)點(diǎn)的運(yùn)行時(shí)間為lgn+k,以前驅(qū)為例,證明如下:
假設(shè)x的左子樹(shù)有k1個(gè)結(jié)點(diǎn),如果k<k1,則k1時(shí)間內(nèi)就可以完成,假設(shè)k1<k,遍歷這k1個(gè)結(jié)點(diǎn)需要k1時(shí)間,找到下一個(gè)前驅(qū)需要往根方向移動(dòng),不妨設(shè)移動(dòng)的距離為h1。如此往復(fù)。假設(shè)期間產(chǎn)生了 k1,k2,k3..,h1,h2…這些數(shù)據(jù)??芍?/span> k1+k2+k3…<=k,h1+h2+…<=樹(shù)的高度。所以運(yùn)行時(shí)間k1+k2+k3+…+h1+h2+…<=lgn+k。
實(shí)際上,如果對(duì)樹(shù)的最小結(jié)點(diǎn)調(diào)用n-1次后繼操作,等同于中序遍歷二叉查找樹(shù)。
?
插入刪除結(jié)點(diǎn)
插入一個(gè)結(jié)點(diǎn)與查找一個(gè)關(guān)鍵字的過(guò)程是基本一致的。當(dāng)查找過(guò)程到達(dá)nil時(shí),這個(gè)位置就是插入的位置。
刪除的過(guò)程要稍微復(fù)雜一點(diǎn):
(1)?????? 如果結(jié)點(diǎn)沒(méi)有子節(jié)點(diǎn),則直接刪除。
(2)?????? 如果結(jié)點(diǎn)只有左子樹(shù)或右子樹(shù),則刪除該節(jié)點(diǎn),然后用該子樹(shù)的根節(jié)點(diǎn)來(lái)取代該節(jié)點(diǎn)的位置。
(3)?????? 如果該節(jié)點(diǎn)有左右子樹(shù),則將該節(jié)點(diǎn)的數(shù)據(jù)與其前驅(qū)或后繼結(jié)點(diǎn)的數(shù)據(jù)進(jìn)行交換,再刪除該前驅(qū)或后繼結(jié)點(diǎn)
?
隨機(jī)構(gòu)造的二叉查找樹(shù)
二叉查找樹(shù)的操作性能依賴(lài)于樹(shù)的高度,為了避免壞的關(guān)鍵字順序造成樹(shù)的高度過(guò)高,可以采用隨機(jī)化的手段來(lái)構(gòu)造樹(shù)。可以證明,隨機(jī)構(gòu)造的二叉查找樹(shù)的期望高度為O(lgn)。
先定義三個(gè)隨機(jī)變量:
Xn:n個(gè)結(jié)點(diǎn)的二叉查找樹(shù)的高度;
Yn:指數(shù)高度Yn=2Xn;Yn = 2*max(Yi-1,Yn-i)。
Rn:根節(jié)點(diǎn)的在關(guān)鍵字中的統(tǒng)計(jì)順序。
Zn,i:定義指示器隨機(jī)變量Zn,i=I{Rn=i}; E[Zn,i] = 1/n。
推理過(guò)程如下:
????????????????????????????????????????????????????????????????????
利用恒等式:,用數(shù)學(xué)歸納得出,再利用jensen不等式:,可得E[Xn] = O(lgn)。
?
?
?
?
隨機(jī)構(gòu)造二叉查找樹(shù)與隨機(jī)化快速排序比較
在構(gòu)造二叉樹(shù)的時(shí)候,當(dāng)選定某個(gè)關(guān)鍵字稱(chēng)為根節(jié)點(diǎn)之后,那么比這個(gè)關(guān)鍵字大的關(guān)鍵字都將出現(xiàn)在該節(jié)點(diǎn)的右字?jǐn)?shù),小的關(guān)鍵字都將出現(xiàn)在左子樹(shù)。這個(gè)過(guò)程與快速排序選定中軸節(jié)點(diǎn)的過(guò)程及其相似。進(jìn)一步,所有的結(jié)點(diǎn)都將與根節(jié)點(diǎn)進(jìn)行比較,但左子樹(shù)中的結(jié)點(diǎn)不會(huì)與右子樹(shù)的結(jié)點(diǎn)比較,反之亦然??梢钥闯鰳?gòu)造二叉查找樹(shù)的過(guò)程與快速排序的過(guò)程驚人地相似,實(shí)際上如果將選定根節(jié)點(diǎn)和選定中軸結(jié)點(diǎn)相對(duì)應(yīng),那么兩者整個(gè)過(guò)程中所進(jìn)行的元素比較是完全相同的,只是順序不一致而已。
?
可以分析二叉查找樹(shù)的平均結(jié)點(diǎn)深度。每個(gè)結(jié)點(diǎn)的深度等于其在插入樹(shù)的過(guò)程中的比較次數(shù),所有的比較次數(shù)之和平均為nlgn,因此平均的結(jié)點(diǎn)深度為lgn。
?
思考題
基數(shù)樹(shù):
基數(shù)樹(shù)數(shù)據(jù)結(jié)構(gòu),用來(lái)存儲(chǔ)0,1位串,位置串并沒(méi)有存儲(chǔ)在節(jié)點(diǎn)中,一個(gè)結(jié)點(diǎn)只要標(biāo)明從根到該節(jié)點(diǎn)的路徑是否構(gòu)成一個(gè)有效位串。當(dāng)查找某關(guān)鍵字a=a0a1…ap,時(shí),在深度為i的一個(gè)結(jié)點(diǎn)處,如果ai=0,則向左轉(zhuǎn),如果ai=1則向右轉(zhuǎn)。下圖的基數(shù)樹(shù)存儲(chǔ)了位串0,001,10, 100,1011.白色結(jié)點(diǎn)為有效位串的終結(jié)結(jié)點(diǎn)。
設(shè)S為一組不同的二進(jìn)制構(gòu)成的集合,各串的長(zhǎng)度之和為n。說(shuō)明如何利用基數(shù)樹(shù),在Θ(n)時(shí)間內(nèi)將S按字典順序排序。
?
分析:構(gòu)造基數(shù)樹(shù)的過(guò)程很顯然,假設(shè)一個(gè)位串的長(zhǎng)度為k,則只需要時(shí)間k就可以將串插入基數(shù)樹(shù)中。然后進(jìn)行中序遍歷就可以,按序輸出。
如果將基數(shù)樹(shù)擴(kuò)展,是否可以用來(lái)存儲(chǔ)一般的字符串,并加快查找過(guò)程?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/longhuihu/archive/2011/02/26/10423370.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的算法导论第十二章:二叉查找树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。