• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woaidongmao

            文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評(píng)論 - 661, 引用 - 0
            數(shù)據(jù)加載中……

            從B樹談到R樹之B樹的c實(shí)現(xiàn)

            http://blog.csdn.net/v_july_v/article/details/6735293(該博客值得深入翻閱)

             

             B樹談到R樹之B樹的c實(shí)現(xiàn)

            作者:weedge,July。編程藝術(shù)室出品。

            前言

                代碼大全的作者Steve McConnell曾稱,他所見識(shí)的任何一本書都不是某一個(gè)人能完全獨(dú)立即能完成的。吾深以為然。

                blog內(nèi)的文章十有八九系我個(gè)人參考資料原創(chuàng)所作,同時(shí)十有二三系本人與吾的朋友共同創(chuàng)作完成。所以,諸君在瀏覽本博客內(nèi)任何一篇文章時(shí),務(wù)必尊重他人勞動(dòng)成果。當(dāng)然,有任何問題,歡迎隨時(shí)不吝指正。

                ok,在本blog之前的一篇文章中:B樹、B+樹、B*樹談到R ,各位讀者反應(yīng)熱烈。這次,咱們來編碼實(shí)現(xiàn)B樹的查找,插入,刪除等操作。同時(shí)此文也算作是上一篇文章從B樹談到R樹的續(xù)。望諸君不吝賜教。謝謝。

            第一部分、B樹的查找,插入,刪除等具體操作

                編碼實(shí)現(xiàn)B樹之前,咱們先來回顧一下上文中所給出的B樹的查找,插入,刪除等具體的操作都是怎么一回事兒。明白了原理之后,再來編程實(shí)現(xiàn),就相對(duì)來說有方向感了。ok,請(qǐng)看下文(援引自B樹、B+樹、B*樹談到R 3小節(jié)):

            B樹的插入、刪除操作

                上文第3小節(jié)簡單介紹了利用B樹這種結(jié)構(gòu)如何訪問外存磁盤中的數(shù)據(jù)的情況,下面咱們通過另外一個(gè)實(shí)例來對(duì)這棵B樹的插入(insert,刪除(delete)基本操作進(jìn)行詳細(xì)的介紹。

                但在此之前,咱們還得簡單回顧下一棵m階的B (m叉樹)的特性,如下:

            1. 樹中每個(gè)結(jié)點(diǎn)含有最多含有m個(gè)孩子,即m滿足:ceil(m/2)<=m<=m
            2. 除根結(jié)點(diǎn)和葉子結(jié)點(diǎn)外,其它每個(gè)結(jié)點(diǎn)至少有[ceil(m / 2)]個(gè)孩子(其中ceil(x)是一個(gè)取上限的函數(shù));
            3. 若根結(jié)點(diǎn)不是葉子結(jié)點(diǎn),則至少有2個(gè)孩子(特殊情況:沒有孩子的根結(jié)點(diǎn),即根結(jié)點(diǎn)為葉子結(jié)點(diǎn),整棵樹只有一個(gè)根節(jié)點(diǎn));
            4. 所有葉子結(jié)點(diǎn)都出現(xiàn)在同一層,葉子結(jié)點(diǎn)不包含任何關(guān)鍵字信息(可以看做是外部接點(diǎn)或查詢失敗的接點(diǎn),實(shí)際上這些結(jié)點(diǎn)不存在,指向這些結(jié)點(diǎn)的指針都為null)
            5. 每個(gè)非終端結(jié)點(diǎn)中包含有n個(gè)關(guān)鍵字信息: (n,P0K1P1,K2,P2,......,KnPn)。其中:
                     a)   Ki (i=1...n)
              為關(guān)鍵字,且關(guān)鍵字按順序升序排序K(i-1)< Ki。
                     b)   Pi
              為指向子樹根的接點(diǎn),且指針P(i-1)指向子樹種所有結(jié)點(diǎn)的關(guān)鍵字均小于Ki,但都大于K(i-1) 
                     c)  
              除根結(jié)點(diǎn)之外的結(jié)點(diǎn)的關(guān)鍵字的個(gè)數(shù)n必須滿足: [ceil(m / 2)-1]<= n <= m-1(葉子結(jié)點(diǎn)也必須滿足此條關(guān)于關(guān)鍵字?jǐn)?shù)的性質(zhì),根結(jié)點(diǎn)除外)。

                ok,下面咱們以一棵5階(m=5,即除根結(jié)點(diǎn)和葉子結(jié)點(diǎn)之外的內(nèi)結(jié)點(diǎn)最多5個(gè)孩子,最少3個(gè)孩子)B樹實(shí)例進(jìn)行講。

            備注:

            • 關(guān)鍵字?jǐn)?shù)(2-4個(gè))針對(duì)--非根結(jié)點(diǎn)(包括葉子結(jié)點(diǎn)在內(nèi)),孩子數(shù)(3-5個(gè))--針對(duì)根結(jié)點(diǎn)和葉子結(jié)點(diǎn)之外的內(nèi)結(jié)點(diǎn)。當(dāng)然,根結(jié)點(diǎn)是必須至少有2個(gè)孩子的,不然就成直線型搜索樹了。
            • 我說的再明白點(diǎn)就是,一棵5階的B樹中任何一個(gè)結(jié)點(diǎn)的關(guān)鍵字?jǐn)?shù)是1-4,孩子樹是2-5。同時(shí),一棵5階的B樹的最大高度應(yīng)為log_ceil(m/2)N(下劃線表示以ceil(m/2)為底)。

            下圖中關(guān)鍵字為大寫字母,順序?yàn)樽帜干颉?/span>

            結(jié)點(diǎn)定義如下:

            typedef struct{
               int Count;         //
            當(dāng)前節(jié)點(diǎn)中關(guān)鍵元素?cái)?shù)目
               ItemType Key[4];   //
            存儲(chǔ)關(guān)鍵字元素的數(shù)組
               long Branch[5];    //
            偽指針數(shù)組,(記錄數(shù)目)方便判斷合并和分裂的情況
            } NodeType;

             

            clip_image001

            1.1、插入(insert)操作

                插入一個(gè)元素時(shí),首先在B樹中是否存在,如果不存在,即在葉子結(jié)點(diǎn)處結(jié)束,然后在葉子結(jié)點(diǎn)中插入該新的元素,注意:

            • 如果葉子結(jié)點(diǎn)空間足夠,這里需要向右移動(dòng)該葉子結(jié)點(diǎn)中大于新插入關(guān)鍵字的元素,
            • 如果空間滿了以致沒有足夠的空間去添加新的元素,則將該結(jié)點(diǎn)進(jìn)行分裂,將一半數(shù)量的關(guān)鍵字元素分裂到新的其相鄰右結(jié)點(diǎn)中,中間關(guān)鍵字元素上移到父結(jié)點(diǎn)中(當(dāng)然,如果父結(jié)點(diǎn)空間滿了,也同樣需要分裂操作),而且當(dāng)結(jié)點(diǎn)中關(guān)鍵元素向右移動(dòng)了,相關(guān)的指針也需要向右移。
            • 如果在根結(jié)點(diǎn)插入新元素,空間滿了,則進(jìn)行分裂操作,這樣原來的根結(jié)點(diǎn)中的中間關(guān)鍵字元素向上移動(dòng)到新的根結(jié)點(diǎn)中,因此導(dǎo)致樹的高度增加一層。

            1、咱們通過一個(gè)實(shí)例來逐步講解下。插入以下字符字母到一棵空的B 樹中(非根結(jié)點(diǎn)關(guān)鍵字?jǐn)?shù)小了(小于2個(gè))就合并,大了(超過4個(gè))就分裂):C N G A H E K Q M F W L T Z D P R X Y S,首先,結(jié)點(diǎn)空間足夠,4個(gè)字母插入相同的結(jié)點(diǎn)中,如下圖:

             clip_image002

            2、當(dāng)咱們?cè)囍迦?/span>H時(shí),結(jié)點(diǎn)發(fā)現(xiàn)空間不夠,以致將其分裂成2個(gè)結(jié)點(diǎn),移動(dòng)中間元素G上移到新的根結(jié)點(diǎn)中,在實(shí)現(xiàn)過程中,咱們把AC留在當(dāng)前結(jié)點(diǎn)中,而HN放置新的其右鄰居結(jié)點(diǎn)中。如下圖:

             clip_image003

            3、當(dāng)咱們插入E,K,Q時(shí),不需要任何分裂操作

            clip_image004

            4、插入M需要一次分裂,注意M恰好是中間關(guān)鍵字元素,以致向上移到父節(jié)點(diǎn)中

             

            clip_image005

            5、插入F,W,L,T不需要任何分裂操作

             

            clip_image006

            6、插入Z時(shí),最右的葉子結(jié)點(diǎn)空間滿了,需要進(jìn)行分裂操作,中間元素T上移到父節(jié)點(diǎn)中,注意通過上移中間元素,樹最終還是保持平衡,分裂結(jié)果的結(jié)點(diǎn)存在2個(gè)關(guān)鍵字元素。

             

            clip_image007

            7、插入D時(shí),導(dǎo)致最左邊的葉子結(jié)點(diǎn)被分裂,D恰好也是中間元素,上移到父節(jié)點(diǎn)中,然后字母P,R,X,Y陸續(xù)插入不需要任何分裂操作(別忘了,樹中至多5個(gè)孩子)。

             

            clip_image008

            8、最后,當(dāng)插入S時(shí),含有N,P,Q,R的結(jié)點(diǎn)需要分裂,把中間元素Q上移到父節(jié)點(diǎn)中,但是情況來了,父節(jié)點(diǎn)中空間已經(jīng)滿了,所以也要進(jìn)行分裂,將父節(jié)點(diǎn)中的中間元素M上移到新形成的根結(jié)點(diǎn)中,注意以前在父節(jié)點(diǎn)中的第三個(gè)指針在修改后包括DG節(jié)點(diǎn)中。這樣具體插入操作的完成,下面介紹刪除操作,刪除操作相對(duì)于插入操作要考慮的情況多點(diǎn)。

             

            clip_image009

            1.2、刪除(delete)操作

                首先查找B樹中需刪除的元素,如果該元素在B樹中存在,則將該元素在其結(jié)點(diǎn)中進(jìn)行刪除,如果刪除該元素后,首先判斷該元素是否有左右孩子結(jié)點(diǎn),如果有,則上移孩子結(jié)點(diǎn)中的某相近元素到父節(jié)點(diǎn)中,然后是移動(dòng)之后的情況;如果沒有,直接刪除后,移動(dòng)之后的情況。

                刪除元素,移動(dòng)相應(yīng)元素之后,

            • 如果某結(jié)點(diǎn)中元素?cái)?shù)目(即關(guān)鍵字?jǐn)?shù))小于ceil(m/2)-1,則需要看其某相鄰兄弟結(jié)點(diǎn)是否豐滿(結(jié)點(diǎn)中元素個(gè)數(shù)大于ceil(m/2)-1)(還記得第一節(jié)中關(guān)于B樹的第5個(gè)特性中的c點(diǎn)么? c)除根結(jié)點(diǎn)之外的結(jié)點(diǎn)(包括葉子結(jié)點(diǎn))的關(guān)鍵字的個(gè)數(shù)n必須滿足: ceil(m / 2)-1<= n <= m-1。m表示最多含有m個(gè)孩子,n表示關(guān)鍵字?jǐn)?shù)。在本小節(jié)中舉的一顆B樹的示例中,關(guān)鍵字?jǐn)?shù)n滿足:2<=n<=4),
            • 如果豐滿,則向父節(jié)點(diǎn)借一個(gè)元素來滿足條件;
            • 如果其相鄰兄弟都剛脫貧,即借了之后其結(jié)點(diǎn)數(shù)目小于ceil(m/2)-1,則該結(jié)點(diǎn)與其相鄰的某一兄弟結(jié)點(diǎn)進(jìn)行合并成一個(gè)結(jié)點(diǎn),以此來滿足條件。

                那咱們通過下面實(shí)例來詳細(xì)了解吧。

                以上述插入操作構(gòu)造的一棵5B樹(樹中最多含有mm=5)個(gè)孩子,因此關(guān)鍵字?jǐn)?shù)最小為ceil(m / 2)-1=2。還是這句話,關(guān)鍵字?jǐn)?shù)小了(小于2個(gè))就合并,大了(超過4個(gè))就分裂)為例,依次刪除H,T,R,E

            clip_image009

            1、首先刪除元素H,當(dāng)然首先查找H,H在一個(gè)葉子結(jié)點(diǎn)中,且該葉子結(jié)點(diǎn)元素?cái)?shù)目3大于最小元素?cái)?shù)目ceil(m/2)-1=2,則操作很簡單,咱們只需要移動(dòng)K至原來H的位置,移動(dòng)LK的位置(也就是結(jié)點(diǎn)中刪除元素后面的元素向前移動(dòng))

             

            clip_image010

            2、下一步,刪除T,因?yàn)?/span>T沒有在葉子結(jié)點(diǎn)中,而是在中間結(jié)點(diǎn)中找到,咱們發(fā)現(xiàn)他的繼承者W(字母升序的下個(gè)元素),將W上移到T的位置,然后將原包含W的孩子結(jié)點(diǎn)中的W進(jìn)行刪除,這里恰好刪除W后,該孩子結(jié)點(diǎn)中元素個(gè)數(shù)大于2,無需進(jìn)行合并操作。

             

            clip_image011

            3、下一步刪除RR在葉子結(jié)點(diǎn)中,但是該結(jié)點(diǎn)中元素?cái)?shù)目為2,刪除導(dǎo)致只有1個(gè)元素,已經(jīng)小于最小元素?cái)?shù)目ceil(5/2)-1=2,而由前面我們已經(jīng)知道:如果其某個(gè)相鄰兄弟結(jié)點(diǎn)中比較豐滿(元素個(gè)數(shù)大于ceil(5/2)-1=2),則可以向父結(jié)點(diǎn)借一個(gè)元素,然后將最豐滿的相鄰兄弟結(jié)點(diǎn)中上移最后或最前一個(gè)元素到父節(jié)點(diǎn)中(有沒有看到紅黑樹中左旋操作的影子?),在這個(gè)實(shí)例中,右相鄰兄弟結(jié)點(diǎn)中比較豐滿(3個(gè)元素大于2),所以先向父節(jié)點(diǎn)借一個(gè)元素W下移到該葉子結(jié)點(diǎn)中,代替原來S的位置,S前移;然后X在相鄰右兄弟結(jié)點(diǎn)中上移到父結(jié)點(diǎn)中,最后在相鄰右兄弟結(jié)點(diǎn)中刪除X,后面元素前移。

             

            clip_image012

            4、最后一步刪除E, 刪除后會(huì)導(dǎo)致很多問題,因?yàn)?/span>E所在的結(jié)點(diǎn)數(shù)目剛好達(dá)標(biāo),剛好滿足最小元素個(gè)數(shù)(ceil(5/2)-1=2,而相鄰的兄弟結(jié)點(diǎn)也是同樣的情況,刪除一個(gè)元素都不能滿足條件,所以需要該節(jié)點(diǎn)與某相鄰兄弟結(jié)點(diǎn)進(jìn)行合并操作;首先移動(dòng)父結(jié)點(diǎn)中的元素(該元素在兩個(gè)需要合并的兩個(gè)結(jié)點(diǎn)元素之間)下移到其子結(jié)點(diǎn)中,然后將這兩個(gè)結(jié)點(diǎn)進(jìn)行合并成一個(gè)結(jié)點(diǎn)。所以在該實(shí)例中,咱們首先將父節(jié)點(diǎn)中的元素D下移到已經(jīng)刪除E而只有F的結(jié)點(diǎn)中,然后將含有DF的結(jié)點(diǎn)和含有A,C的相鄰兄弟結(jié)點(diǎn)進(jìn)行合并成一個(gè)結(jié)點(diǎn)。

             

            clip_image013

            5、也許你認(rèn)為這樣刪除操作已經(jīng)結(jié)束了,其實(shí)不然,在看看上圖,對(duì)于這種特殊情況,你立即會(huì)發(fā)現(xiàn)父節(jié)點(diǎn)只包含一個(gè)元素G,沒達(dá)標(biāo)(因?yàn)榉歉?jié)點(diǎn)包括葉子結(jié)點(diǎn)的關(guān)鍵字?jǐn)?shù)n必須滿足于2=<n<=4,而此處的n=1),這是不能夠接受的。如果這個(gè)問題結(jié)點(diǎn)的相鄰兄弟比較豐滿,則可以向父結(jié)點(diǎn)借一個(gè)元素。假設(shè)這時(shí)右兄弟結(jié)點(diǎn)(含有Q,X)有一個(gè)以上的元素(Q右邊還有元素),然后咱們將M下移到元素很少的子結(jié)點(diǎn)中,將Q上移到M的位置,這時(shí),Q的左子樹將變成M的右子樹,也就是含有NP結(jié)點(diǎn)被依附在M的右指針上。所以在這個(gè)實(shí)例中,咱們沒有辦法去借一個(gè)元素,只能與兄弟結(jié)點(diǎn)進(jìn)行合并成一個(gè)結(jié)點(diǎn),而根結(jié)點(diǎn)中的唯一元素M下移到子結(jié)點(diǎn),這樣,樹的高度減少一層。

             

            clip_image014

            為了進(jìn)一步詳細(xì)討論刪除的情況,再舉另外一個(gè)實(shí)例

            這里是一棵不同的5B樹,那咱們?cè)囍鴦h除C

             

            clip_image015

            于是將刪除元素C的右子結(jié)點(diǎn)中的D元素上移到C的位置,但是出現(xiàn)上移元素后,只有一個(gè)元素的結(jié)點(diǎn)的情況。

            又因?yàn)楹?/span>E的結(jié)點(diǎn),其相鄰兄弟結(jié)點(diǎn)才剛脫貧(最少元素個(gè)數(shù)為2),不可能向父節(jié)點(diǎn)借元素,所以只能進(jìn)行合并操作,于是這里將含有A,B的左兄弟結(jié)點(diǎn)和含有E的結(jié)點(diǎn)進(jìn)行合并成一個(gè)結(jié)點(diǎn)。

             

            clip_image016

            這樣又出現(xiàn)只含有一個(gè)元素F結(jié)點(diǎn)的情況,這時(shí),其相鄰的兄弟結(jié)點(diǎn)是豐滿的(元素個(gè)數(shù)為3>最小元素個(gè)數(shù)2),這樣就可以想父結(jié)點(diǎn)借元素了,把父結(jié)點(diǎn)中的J下移到該結(jié)點(diǎn)中,相應(yīng)的如果結(jié)點(diǎn)中J后有元素則前移,然后相鄰兄弟結(jié)點(diǎn)中的第一個(gè)元素(或者最后一個(gè)元素)上移到父節(jié)點(diǎn)中,后面的元素(或者前面的元素)前移(或者后移);注意含有K,L的結(jié)點(diǎn)以前依附在M的左邊,現(xiàn)在變?yōu)橐栏皆?/span>J的右邊。這樣每個(gè)結(jié)點(diǎn)都滿足B樹結(jié)構(gòu)性質(zhì)。

             

            clip_image017

            從以上操作可看出:除根結(jié)點(diǎn)之外的結(jié)點(diǎn)(包括葉子結(jié)點(diǎn))的關(guān)鍵字的個(gè)數(shù)n滿足:(ceil(m / 2)-1<= n <= m-1,即2<=n<=4。這也佐證了咱們之前的觀點(diǎn)。刪除操作完。

            第二部分、B樹的編碼實(shí)現(xiàn)

                既然明白了B樹的插入,和刪除操作的原理,接下來,咱們來一步一步實(shí)現(xiàn)它。不過,有一點(diǎn)必須說明的是:這個(gè)實(shí)現(xiàn)只是實(shí)現(xiàn)了偶數(shù)序order(階)的情況;還有奇數(shù)序order(階)的情況沒有考慮。待日后改進(jìn)。

            • ok,以下是頭文件:

            • 下面是B樹的實(shí)現(xiàn)文件:

            • 最后,給出測(cè)試文件:

            參考

            • http://www.shnenglu.com/converse/archive/2009/10/13/98521.html

            聯(lián)系作者:

                若有任何問題,歡迎隨時(shí)不吝指正?;蛘呗?lián)系我們:

            后記:

                blog日后會(huì)更多的關(guān)注數(shù)據(jù)結(jié)構(gòu)與算法之外的東西,如分布式架構(gòu),海量數(shù)據(jù)處理,搜索引擎相關(guān)。畢竟,算法之外的東西,如瀚海般無止境,要學(xué)的東西,還有很多。

                若轉(zhuǎn)載,請(qǐng)注明出處,謝謝。完。二零一一年八月三十一日。

             

            posted on 2011-09-01 11:02 肥仔 閱讀(2245) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++ 基礎(chǔ) 、數(shù)據(jù)庫

            日韩亚洲国产综合久久久| 久久人人爽人人爽人人片AV麻豆| 精品熟女少妇AV免费久久| 狠狠色丁香婷婷久久综合| 久久综合给久久狠狠97色| 97久久香蕉国产线看观看| 国产香蕉97碰碰久久人人| 久久综合亚洲色HEZYO社区| 久久一日本道色综合久久| 94久久国产乱子伦精品免费| 人妻无码αv中文字幕久久琪琪布 人妻无码精品久久亚瑟影视 | 91精品久久久久久无码| 青青草原综合久久大伊人导航| 无码人妻久久久一区二区三区| 国产精品成人无码久久久久久| 色综合久久久久无码专区 | 99久久国产综合精品女同图片| 久久综合狠狠色综合伊人| 久久人妻AV中文字幕| 国产精品成人99久久久久| 久久久精品人妻一区二区三区四| 精品久久久久一区二区三区| 久久久久久久久久久久中文字幕| 久久久久久亚洲精品无码| 久久99中文字幕久久| 亚洲色大成网站WWW久久九九| 99久久免费只有精品国产| 99精品久久久久久久婷婷| 亚洲?V乱码久久精品蜜桃 | 无码人妻精品一区二区三区久久久| 久久久久99精品成人片三人毛片| 久久国产乱子伦免费精品| 亚洲va国产va天堂va久久| 亚洲国产成人久久一区久久| 久久国产一片免费观看| 久久精品国产亚洲综合色| 国内精品久久久久影院优| 久久综合狠狠综合久久| 99久久精品午夜一区二区| 国产精品九九九久久九九| 99久久免费国产精精品|