1. 程式人生 > >資料結構--樹形結構

資料結構--樹形結構

  • 平衡二叉樹

    這裡寫圖片描述

這是個平衡樹,一個節點下只有小於兩個子葉節點。

該樹想要達成有效查詢,勢必需要維持如下一種結構:
    樹的子葉節點中,左子樹一定小於等於當前節點,而當前節點的右子樹則一定大於當前節點。只有這樣,才能夠維持全域性有序,才能夠進行查詢。
    這也就決定了只有取得某一個子葉節點後,才能夠根據這個節點知道他的子樹的具體的值情況。這點非常之重要,因為二叉平衡樹,只有兩個子葉節點,所以如果想找到某個資料,他必須重複更多次“拿到一個節點的兩個子節點,判斷大小,再從其中一個子節點取出他的兩個子節點,判斷大小。”這一過程。
    這個過程重複的次數,就是**樹的高度**。那麼既然每個子樹只有兩個節點,那麼N
個數據的樹的高度也就很容易可以算出了。 樹的儲存結構: 順序儲存結構:類似陣列形式(查詢快,插入慢) 鏈式儲存結構:類似連結串列形式(查詢的時候需要大量的尋道時間) 優點: 沒有空間浪費,不會存在空餘的空間,而且查詢速度比較快。 缺點: 需要取出多個節點,且無法預測下一個節點的位置。這種取出的操作,在記憶體內進行的時候,速度很快,但如果到磁碟,那麼就意味著大量隨機尋道。基本磁碟就被查死了。
  • b樹
b樹:平衡二叉樹+順序儲存結構
    b樹,因為其構建過程中引入了有序陣列,從而有效的降低了樹的高度,一次取出一個連續的陣列,這個操作在磁碟上比取出與陣列相同數量的離散資料,要便宜的多。因此磁碟上基本都是b樹結構。

缺點:
    與二叉樹相比,他會耗費更多的空間。在最惡劣的情況下,要有幾乎是元資料兩倍的格子才能裝得下整個資料集(當樹的所有節點都進行了分裂後)。

b樹插入:

這裡寫圖片描述

B樹在插入的時候,如果是最後一個node,那麼速度非常快,因為是順序寫。

b樹更新:

這裡寫圖片描述
但如果有更新插入刪除等綜合寫入,最後因為需要迴圈利用磁碟塊,所以會出現較多的隨機io.大量時間消耗在磁碟尋道時間上。

執行時間很長的b樹:

這裡寫圖片描述

如果是一個執行時間很長的b樹,那麼幾乎所有的請求,都是隨機io。因為磁碟塊本身已經不再連續,很難保證可以順序讀取。

如何能夠解決這個問題呢?

1: 放棄部分讀效能,使用更加面向順序寫的樹的結構來提升寫效能:
(1),COLA(Cache-Oblivious Look ahead Array)(代表應用自然是tokuDB)。
(2),LSM tree(Log-structured merge Tree)或SSTABLE(代表的資料集是cassandra,hbase,bdb java editon,levelDB etc.)
2:使用ssd,讓尋道成為往事。

  • B+樹
B+樹:平衡二叉樹+鏈式儲存結構
    b+樹在查詢過程中應該是不會慢的,但如果資料插入比較無序的時候,比如先插入5 然後10000然後3然後800 這樣跨度很大的資料的時候,就需要先“找到這個資料應該被插入的位置”,然後插入資料。這個查詢到位置的過程,如果非常離散,那麼就意味著每次查詢的時候,他的子節點都不在記憶體中,這時候就必須使用磁碟尋道時間查詢。更新基本與插入是相同的。
    目前關係型資料庫大部分採用該儲存結構。
  • LSM樹
理解:在記憶體進行寫操作(插入、修改、刪除),達到一定閥值之後,持久化到磁碟。
    資料首先會插入記憶體中的樹。當記憶體樹的資料量超過設定閾值後,會進行合併操作。合併操作會從左至右便利記憶體中樹的子節點 與 磁碟中樹的子節點並進行合併,會用最新更新的資料覆蓋舊的資料(或者記錄為不同版本)。當被合併合併資料量達到磁碟的儲存頁大小時。會將合併後的資料(有序的)持久化到磁碟,同時更新父節點對子節點的指標。(類似於定時對磁碟中的資料排序)
    讀資料:從磁碟中把父節點的資料拿出來,在記憶體中快取。
    寫資料:如果記憶體中有該節點的資料,則進行直接進行操作。如果不存在則進行讀資料。達到一定閥值後持久化到磁碟上。