2-3 树
轉(zhuǎn)自:http://www.cnblogs.com/yangecnu/p/Introduce-2-3-Search-Tree.html
?
前面介紹了二叉查找樹(Binary Search Tree),他對于大多數(shù)情況下的查找和插入在效率上來說是沒有問題的,但是他在最差的情況下效率比較低。本文及后面文章介紹的平衡查找樹的數(shù)據(jù)結(jié)構(gòu)能夠保證在最差的情況下也能達到lgN的效率,要實現(xiàn)這一目標我們需要保證樹在插入完成之后始終保持平衡狀態(tài),這就是平衡查找樹(Balanced Search Tree)。在一棵具有N 個節(jié)點的樹中,我們希望該樹的高度能夠維持在lgN左右,這樣我們就能保證只需要lgN次比較操作就可以查找到想要的值。不幸的是,每次插入元素之后維持樹的平衡狀態(tài)太昂貴。所以這里會介紹一些新的數(shù)據(jù)結(jié)構(gòu)來保證在最壞的情況下插入和查找效率都能保證在對數(shù)的時間復雜度內(nèi)完成。本文首先介紹2-3查找樹(2-3 Search Tree),后面會在此基礎(chǔ)上介紹紅黑樹和B樹。
定義
和二叉樹不一樣,2-3樹運行每個節(jié)點保存1個或者兩個的值。對于普通的2節(jié)點(2-node),他保存1個key和左右兩個子節(jié)點。對應3節(jié)點(3-node),保存兩個Key,2-3查找樹的定義如下:
1. 要么為空,要么:
2. 對于2節(jié)點,該節(jié)點保存一個key及對應value,以及兩個指向左右節(jié)點的指針,左節(jié)點也是一個2-3節(jié)點,所有的值都比key小,又節(jié)點也是一個2-3節(jié)點,所有的值比key要大。
3. 對于3節(jié)點,該節(jié)點保存兩個key及對應value,以及三個指向左中右的節(jié)點的指針。左節(jié)點也是一個2-3節(jié)點,所有的值均比兩個key中的最小的key還要小;中間節(jié)點也是一個2-3節(jié)點,中間節(jié)點的key值在兩個跟節(jié)點key值之間;右節(jié)點也是一個2-3節(jié)點,節(jié)點的所有key值比兩個key中的最大的key還要大。
如果中序遍歷2-3查找樹,就可以得到排好序的序列。在一個完全平衡的2-3查找樹中,根節(jié)點到每一個葉子節(jié)點的距離都相同。
完全平衡的2-3查找樹,每個根節(jié)點到葉子節(jié)點的距離是相同的。
查找
在進行2-3樹的平衡之前,我們先假設已經(jīng)處于平衡狀態(tài),我們先看基本的查找操作。
2-3樹的查找和二叉查找樹類似,要確定一個樹是否屬于2-3樹,我們首先和其跟節(jié)點進行比較,如果相等,則查找成功;否則根據(jù)比較的條件,在其左中右子樹中遞歸查找,如果找到的節(jié)點為空,則未找到,否則返回。查找過程如下圖:
插入
往一個2-node節(jié)點插入
往2-3樹中插入元素和往二叉查找樹中插入元素一樣,首先要進行查找,然后將節(jié)點掛到未找到的節(jié)點上。2-3樹之所以能夠保證在最差的情況下的效率的原因在于其插入之后仍然能夠保持平衡狀態(tài)。如果查找后未找到的節(jié)點是一個2-node節(jié)點,那么很容易,我們只需要將新的元素放到這個2-node節(jié)點里面使其變成一個3-node節(jié)點即可。但是如果查找的節(jié)點結(jié)束于一個3-node節(jié)點,那么可能有點麻煩。
往一個3-node節(jié)點插入
往一個3-node節(jié)點插入一個新的節(jié)點可能會遇到很多種不同的情況,下面首先從一個最簡單的只包含一個3-node節(jié)點的樹開始討論。
只包含一個3-node節(jié)點
?
?
如上圖,假設2-3樹只包含一個3-node節(jié)點,這個節(jié)點有兩個key,沒有空間來插入第三個key了,最自然的方式是我們假設這個節(jié)點能存放三個元素,暫時使其變成一個4-node節(jié)點,同時他包含四個子節(jié)點。然后,我們將這個4-node節(jié)點的中間元素提升,左邊的節(jié)點作為其左節(jié)點,右邊的元素作為其右節(jié)點。插入完成,變?yōu)槠胶?-3查找樹,樹的高度從0變?yōu)?。
節(jié)點是3-node,父節(jié)點是2-node
和第一種情況一樣,我們也可以將新的元素插入到3-node節(jié)點中,使其成為一個臨時的4-node節(jié)點,然后,將該節(jié)點中的中間元素提升到父節(jié)點即2-node節(jié)點中,使其父節(jié)點成為一個3-node節(jié)點,然后將左右節(jié)點分別掛在這個3-node節(jié)點的恰當位置。操作如下圖:
節(jié)點是3-node,父節(jié)點也是3-node
當我們插入的節(jié)點是3-node的時候,我們將該節(jié)點拆分,中間元素提升至父節(jié)點,但是此時父節(jié)點是一個3-node節(jié)點,插入之后,父節(jié)點變成了4-node節(jié)點,然后繼續(xù)將中間元素提升至其父節(jié)點,直至遇到一個父節(jié)點是2-node節(jié)點,然后將其變?yōu)?-node,不需要繼續(xù)進行拆分。
?
?
?
根節(jié)點分裂
當根節(jié)點到字節(jié)點都是3-node節(jié)點的時候,這是如果我們要在字節(jié)點插入新的元素的時候,會一直查分到根節(jié)點,在最后一步的時候,根節(jié)點變成了一個4-node節(jié)點,這個時候,就需要將跟節(jié)點查分為兩個2-node節(jié)點,樹的高度加1;
?
?
本地轉(zhuǎn)換
將一個4-node拆分為2-3node涉及到6種可能的操作。這4-node可能在跟節(jié)點,也可能是2-node的左子節(jié)點或者右子節(jié)點。或者是一個3-node的左,中,右子節(jié)點。所有的這些改變都是本地的,不需要檢查或者修改其他部分的節(jié)點。所以只需要常數(shù)次操作即可完成2-3樹的平衡。
?
性質(zhì)
這些本地操作保持了2-3樹的平衡。對于4-node節(jié)點變形為2-3節(jié)點,變形前后樹的高度沒有發(fā)生變化。只有當跟節(jié)點是4-node節(jié)點,變形后樹的高度才加一。如下圖所示:
?
分析
完全平衡的2-3查找樹如下圖,每個根節(jié)點到葉子節(jié)點的距離是相同的:
2-3樹的查找效率與樹的高度是息息相關(guān)的。
- 在最壞的情況下,也就是所有的節(jié)點都是2-node節(jié)點,查找效率為lgN
- 在最好的情況下,所有的節(jié)點都是3-node節(jié)點,查找效率為log3N約等于0.631lgN
距離來說,對于1百萬個節(jié)點的2-3樹,樹的高度為12-20之間,對于10億個節(jié)點的2-3樹,樹的高度為18-30之間。
對于插入來說,只需要常數(shù)次操作即可完成,因為他只需要修改與該節(jié)點關(guān)聯(lián)的節(jié)點即可,不需要檢查其他節(jié)點,所以效率和查找類似。下面是2-3查找樹的效率:
實現(xiàn)
直接實現(xiàn)2-3樹比較復雜,因為:
2-3查找樹實現(xiàn)起來比較復雜,在某些情況插入后的平衡操作可能會使得效率降低。在2-3查找樹基礎(chǔ)上改進的紅黑樹不僅具有較高的效率,并且實現(xiàn)起來較2-3查找樹簡單。
轉(zhuǎn)載于:https://www.cnblogs.com/Allen-rg/p/7142735.html
總結(jié)
- 上一篇: span居中
- 下一篇: 【转】error while loadi