日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

数据结构与算法--B树原理及实现

發(fā)布時(shí)間:2023/12/4 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构与算法--B树原理及实现 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

B樹(shù)

  • 前幾篇文中討論的數(shù)據(jù)結(jié)構(gòu)我們都是假設(shè)所有的數(shù)據(jù)都存儲(chǔ)在計(jì)算機(jī)的主存中。可說(shuō)總要那么海量的數(shù)據(jù)需要通過(guò)個(gè)中數(shù)據(jù)結(jié)構(gòu)去存儲(chǔ),我們不可能有這么多內(nèi)存區(qū)存放這些數(shù)據(jù)。那么意味著我們需要將他們放磁盤。所以這個(gè)時(shí)候范問(wèn)時(shí)間復(fù)雜度O決定了他是否能適合存儲(chǔ)磁盤,大O模型不適用于磁盤存儲(chǔ)。游戲規(guī)則變了。

  • 在磁盤中操作速度和CPU內(nèi)存計(jì)算速度相差甚遠(yuǎn)。

    • 例如一臺(tái)機(jī)器每秒可以執(zhí)行5億條指令。
    • 磁盤讀寫操作依賴磁盤的機(jī)械運(yùn)動(dòng),磁盤轉(zhuǎn)動(dòng),磁針移動(dòng),也許磁盤7200RPM的轉(zhuǎn)速,1轉(zhuǎn)大約1/120秒,約8.3ms,我們就估算是8.3
    • 每秒大概120次磁盤訪問(wèn)
    • 但是1分鐘7200轉(zhuǎn)比起每秒5億簡(jiǎn)直不是一個(gè)量級(jí),比值相當(dāng)于 40W:1
    • 方法是盡量減少磁盤的操作,寧愿大量計(jì)算
    • 對(duì)于樹(shù)來(lái)說(shuō),一個(gè)節(jié)點(diǎn)存在幾個(gè)子節(jié)點(diǎn),我們?cè)趦?nèi)存中通過(guò)指針尋址,但是在磁盤中需要機(jī)械運(yùn)動(dòng)尋址
案例
  • 我們通過(guò)一個(gè)案例來(lái)結(jié)束典型查找樹(shù)的執(zhí)行方式:
    • 假設(shè)要訪問(wèn)廣東市所有人的出行記錄。假設(shè)只有1kw項(xiàng)數(shù)據(jù)。每個(gè)關(guān)鍵字32字節(jié)(是這個(gè)人的名字+唯一id),而一個(gè)記錄存儲(chǔ)這N個(gè)信息是256個(gè)字節(jié)。假設(shè)這些1kw數(shù)據(jù)不能都存儲(chǔ)進(jìn)主內(nèi)存
    • 更具如上計(jì)算,我們
解決方法
  • 不平衡的二叉查找樹(shù)解決如上問(wèn)題完全不可取,最壞情況他有線性深度,從而可能需要1kw次磁盤的范問(wèn)。平均的話一次成功的查找也需要1.38logN次范圍,由于log10000000 =24 ,1.38*24 = 32/6 = 5秒。AVL樹(shù)多少要好一點(diǎn),1.44logN是最壞情況,平均訪問(wèn)是logN,擇優(yōu)AVL計(jì)算平均25次磁盤查詢一個(gè)數(shù)據(jù),4秒左右

  • 要減少磁盤范問(wèn)次數(shù),比如減到3,4。我們需要更加復(fù)雜的程序。因?yàn)闄C(jī)器指令相對(duì)機(jī)械操作相當(dāng)于不耗時(shí)。以上分析我們知道二叉樹(shù)不可行,減少樹(shù)層級(jí)增加節(jié)點(diǎn)分支的方式來(lái)解決。

  • 31個(gè)節(jié)點(diǎn)的完美二叉樹(shù)有5層,31個(gè)節(jié)點(diǎn)的5叉樹(shù)只有3層

  • 一個(gè)完全二叉樹(shù)的高度大概是log2N,而一顆完全M叉樹(shù)的高度大概是LogMN

  • 我們建立與二叉樹(shù)類似的M叉查找樹(shù),二叉樹(shù)中我們需要一個(gè)key來(lái)決定走左樹(shù)還是右樹(shù),M叉樹(shù)我們需要M-1個(gè)key來(lái)決定

  • 同時(shí)避免M叉樹(shù)退化成鏈表,我們需要給一個(gè)平衡條件,限制M叉樹(shù)退化到二叉樹(shù),那就是B樹(shù)如下性質(zhì)

  • 階為M的B樹(shù)是一顆具有下列特性的樹(shù):

    • 數(shù)據(jù)項(xiàng)存儲(chǔ)在葉子節(jié)點(diǎn)上
    • 非葉子節(jié)點(diǎn)存儲(chǔ)直到M-1個(gè)關(guān)鍵字用來(lái)指示搜索方向;關(guān)鍵字i代表子樹(shù)i+1中最小關(guān)鍵字
    • 數(shù)的根節(jié)點(diǎn)如果不是葉子節(jié)點(diǎn),那么他子節(jié)點(diǎn)個(gè)數(shù)必須在2~M之間
    • 除了根節(jié)點(diǎn)外,所有非葉子節(jié)點(diǎn)的子節(jié)點(diǎn)個(gè)數(shù)必須在M/2~M個(gè)之間
    • 所有葉子節(jié)點(diǎn)都在相同的深度上,并且有L/2和L個(gè)數(shù)據(jù)項(xiàng)目,L個(gè)數(shù)之后確認(rèn)
  • 如下圖5階B樹(shù)的案例,所有非葉子節(jié)點(diǎn)的兒子樹(shù)都在3~5之間(5/2 ~ 5 取整 3-5),那么他們有2-4個(gè)關(guān)鍵字;根可能只有2個(gè)子節(jié)點(diǎn)。這里我們L=5,所有葉子節(jié)點(diǎn)的數(shù)據(jù)項(xiàng)則是(5/2 ~5 取整 3-5 之間)

    • 要求節(jié)點(diǎn)半滿保證B樹(shù)不退化到簡(jiǎn)單二叉樹(shù)
B樹(shù)結(jié)構(gòu)分析
  • 我們根據(jù)所存儲(chǔ)的項(xiàng)的大小選擇M與L的大小,還是上面的案例,我們假設(shè)一個(gè)區(qū)塊的磁盤大小是8192Byte,
  • 每個(gè)關(guān)鍵字32Byte,在一顆M階B數(shù)中,有M-1個(gè)關(guān)鍵字那么總數(shù)是32(M-1),再加上M個(gè)分支(指針int型4Byte),總數(shù)則為32(M-1)+4M = 36M-32
  • 那么一個(gè)片區(qū)8192可以存儲(chǔ)的最大節(jié)點(diǎn)數(shù)據(jù)是8192= (36M-32) , M = 228階,也就是我們每一層有228個(gè)分支
  • 以上案例中條件說(shuō)一個(gè)記錄256Byte,8192/256 = 32 ,一個(gè)片區(qū)可以存儲(chǔ)32個(gè)記錄,我們選擇L=32,這樣一個(gè)子節(jié)點(diǎn)中所有數(shù)據(jù)可以在同一個(gè)片區(qū)(盡量一次磁盤操作可以讀完)
  • 這樣我們保證了每個(gè)葉子節(jié)點(diǎn)有16~32個(gè)數(shù)據(jù)記錄以及每個(gè)內(nèi)部節(jié)點(diǎn)至少有228/2 = 114 中分支方式
  • 那么1kw個(gè)數(shù)據(jù)最多存儲(chǔ)的葉子節(jié)點(diǎn)個(gè)數(shù) 10000000/16 = 625000 個(gè)葉子節(jié)點(diǎn)中
  • 層級(jí)最少情況,每一層都是滿分支(228),625000/228 = 224 /228 = 1,最少的情況第二次就是葉子節(jié)點(diǎn)
  • 層級(jí)最多情況,每一層都是半分支(228/2=114),625000/114 = 5482.4/114=48/1154 = 1 ,最多情況第四層是葉子節(jié)點(diǎn)
  • 如上分析,最壞情況訪問(wèn)次數(shù)近似log(m/2)N給出
構(gòu)造B樹(shù)–添加節(jié)點(diǎn),刪除節(jié)點(diǎn)
插入節(jié)點(diǎn)
  • 我們按照上面圖片中的案例,需要將57 插入到圖中的B樹(shù),沿著樹(shù)向下查找他不在樹(shù)中,我們把它作為第五項(xiàng)數(shù)據(jù)添加到第對(duì)應(yīng)的葉子節(jié)點(diǎn)中如下圖:
方法一
  • 如上更新數(shù)據(jù)分為三步:
    • 第一遍歷B樹(shù),找到插入數(shù)據(jù)的對(duì)應(yīng)位置
    • 讀取樹(shù)葉節(jié)點(diǎn)中數(shù)據(jù)并且重排樹(shù)葉節(jié)點(diǎn)中數(shù)據(jù)
    • 將重排的數(shù)據(jù)寫入樹(shù)葉節(jié)點(diǎn)
  • 與磁盤的操作相比,這些邏輯排列時(shí)間幾乎可以忽略不計(jì),以上是簡(jiǎn)單的模式,因?yàn)楦臉?shù)葉節(jié)點(diǎn)并沒(méi)有被裝滿,現(xiàn)在我們?cè)诓迦?5 到上圖中。
    • 55要插入的那個(gè)葉子節(jié)點(diǎn)已經(jīng)滿,有L+1項(xiàng)數(shù)據(jù),我們需要將他分成兩個(gè)葉子節(jié)點(diǎn),這兩葉子節(jié)點(diǎn)能保證所有需要的記錄的最小個(gè)數(shù),每一個(gè)葉子節(jié)點(diǎn)3個(gè)項(xiàng)(需要兩次磁盤范問(wèn))
    • 接著我們需要更新父節(jié)點(diǎn),將最小的值添加到父節(jié)點(diǎn)中(需要一次寫入的磁盤操作),這種方式是更具上面L/2的規(guī)則執(zhí)行
    • 雖然分離節(jié)點(diǎn)是耗時(shí)的,至少需要2次磁盤操作,但是很少發(fā)生,比如我們上面L=32 時(shí)候每次節(jié)點(diǎn)分裂時(shí)候都有16 或者17 項(xiàng)數(shù)據(jù)的兩片葉子節(jié)點(diǎn),那么我們需要之后的17次添加操作才會(huì)有一次分裂

  • 如上圖情況,當(dāng)一個(gè)非葉子節(jié)點(diǎn)分裂,父節(jié)點(diǎn)得到一個(gè)新的子節(jié)點(diǎn),父節(jié)點(diǎn)也需要增加一個(gè)項(xiàng),如果父節(jié)點(diǎn)此時(shí)也達(dá)到分裂閥值,則需要繼續(xù)向上分裂直到達(dá)到根節(jié)點(diǎn)。如果分裂根就得到兩個(gè)根,這顯然不現(xiàn)實(shí),我們則創(chuàng)建一個(gè)新根,這個(gè)根以分裂得到的兩個(gè)新根為子節(jié)點(diǎn),所以我們的根節(jié)點(diǎn)的子節(jié)點(diǎn)的個(gè)數(shù)設(shè)置在2~M個(gè)是有這個(gè)原因的。
  • 這種方式也是B樹(shù)增加高度的唯一方式
方法二
  • 在相鄰節(jié)點(diǎn)有空間時(shí)候,將一個(gè)子節(jié)點(diǎn)交給鄰節(jié)點(diǎn),例如將上圖中29 節(jié)點(diǎn)插入到B樹(shù)中,我們可以把32移到 下一片樹(shù)葉而騰出一個(gè)空間來(lái),這種方法要求對(duì)父節(jié)點(diǎn)進(jìn)行修改,因?yàn)檫@些關(guān)鍵字也會(huì)受影響,他趨向于是的節(jié)點(diǎn)達(dá)到滿節(jié)點(diǎn),更加節(jié)省空間。
刪除節(jié)點(diǎn)
  • 通過(guò)查找到要?jiǎng)h除的項(xiàng)并在找到后刪除他來(lái)執(zhí)行刪除操作,問(wèn)題在于,如果被刪元素的總元素個(gè)數(shù)已經(jīng)低于最小值(L/2),那么刪除后他的項(xiàng)目就不符合B樹(shù)的要求,我們可以通過(guò)在鄰節(jié)點(diǎn)借一個(gè)節(jié)點(diǎn)來(lái)矯正這種情況,如果鄰節(jié)點(diǎn)也達(dá)到最小值(L/2),那么我們就合并這兩個(gè)葉子節(jié)點(diǎn)結(jié)合成一個(gè)新的滿葉節(jié)點(diǎn)。
  • 這種操作意味著父節(jié)點(diǎn)是去一個(gè)兒子,如果失去兒子節(jié)點(diǎn)后又引發(fā)兒子節(jié)點(diǎn)數(shù)低于下限,我們繼續(xù)使用相同的策略,一直到根節(jié)點(diǎn),如果這個(gè)過(guò)程使得根只剩下一個(gè)子節(jié)點(diǎn),那么刪除這個(gè)根節(jié)點(diǎn),讓原兒子節(jié)點(diǎn)當(dāng)現(xiàn)在B樹(shù)的新根節(jié)點(diǎn)。
  • 這種方式是B樹(shù)降低高度的唯一方式。
  • 如下案例,我們還是依照上圖中的B數(shù),刪除99 項(xiàng)的節(jié)點(diǎn),由于葉子節(jié)點(diǎn)只有兩個(gè),而其鄰節(jié)點(diǎn)以及是最小值3 個(gè)了,因此,我們將這兩個(gè)葉子節(jié)點(diǎn)合并成有5項(xiàng)數(shù)據(jù)的一片新的葉子節(jié)點(diǎn)。結(jié)果他的父節(jié)點(diǎn)只有兩個(gè)子節(jié)點(diǎn),此時(shí)父節(jié)點(diǎn)繼續(xù)上一個(gè)步驟,從鄰節(jié)點(diǎn)領(lǐng)養(yǎng),鄰節(jié)點(diǎn)有4個(gè)子節(jié)點(diǎn),最終使用雙方都得到3個(gè)子節(jié)點(diǎn),如下圖:

上一篇:數(shù)據(jù)結(jié)構(gòu)與算法–AVL樹(shù)原理及實(shí)現(xiàn)
下一篇:數(shù)據(jù)結(jié)構(gòu)與算法–圖論,最短路算法,拓?fù)渑判蛩惴?/p>

總結(jié)

以上是生活随笔為你收集整理的数据结构与算法--B树原理及实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。