1. 程式人生 > >【Algorithms公開課學習筆記9】 符號表part2——平衡搜尋樹

【Algorithms公開課學習筆記9】 符號表part2——平衡搜尋樹

Balanced Search Tree 平衡搜尋樹

0. 前言

上一篇文章,我們分析了二叉搜尋樹(BST傳送門)。在二叉搜尋樹中,查詢、插入、刪除、ceiling和floor等操作的平均時間效能取決於樹高。在極端情況下(如插入有序序列後),如果樹高h過大,其時間效能將會變得很差。根據樹的特點,通過平衡樹操作可以有效地降低樹的高度,從而達到理想的時間效能。這就是本篇文章的重點——平衡搜尋樹(BSTs)。

1. 2-3搜尋樹

基本概念

2-3樹的是由若干個2-節點(2-node)和3-節點(3-node)構成的樹。其基本特徵是有序對稱(symmetric order)和絕對平衡(perfect balance)。 2-節點

:2-節點具有一個key和兩個子連結 3-節點:3-節點具有兩個key和三個子連結 有序對稱:通過中序遍歷將得到遞增的序列(升序序列) 絕對平衡:從根節點到空連結的路徑都是相同長度的

基本操作

查詢操作:對比節點key值,如果大於key,查右子樹;如果小於key,查左子樹;直到等於key或查到空連結。特別地,對於3-節點,如果小於左key,查左子樹;如果大於左key小於右key,查中子樹;如果大於右key,查右子樹;直到等於key或查到為空連結。 插入操作:查詢到該節點key值的合適位置,插入節點。如果該節點變成3-節點,無需操作;如果該節點變成4-節點,則要將中間key值的節點上浮到父節點,以此類推。在上浮過程中,如果root節點成為4-節點,則中間key值節點成為新root節點,左右key值節點分離成為新root節點的子節點。

下圖示意了三種上浮的情況:

效能分析

操作、插入、刪除操作均~clgN,其中係數c取決於實現方法(0< c <1) 分析所得,最壞的情況下是lgN,做好的情況下是log3N(約為0.631 lgN)。

存在問題

現實中,直接實現2-3樹是非常複雜的,主要有以下原因:

  • 維持多種型別的節點是冗餘的(至少需要維持2-節點、3-節點和4-節點)
  • 需要多種比較才能降低樹高
  • 需要增加樹高以分離4-節點
  • 分離節點時的情況太多

2. (左傾)紅黑樹

基本概念

上一節分析了2-3樹存在的問題就是實現起來非常複雜,因此引入了(左傾)紅黑樹來表示2-3樹。(這樣的話,實現紅黑樹就相當於實現了2-3樹)

在紅黑樹中,存在以下特徵:(結合下圖)

  • 沒有節點連線兩條紅連結
  • 每一條從根到空連結的路徑中黑連結的數量的相等的
  • 紅連結都是左傾的

當理解紅黑樹的特徵之後,接著看看用紅黑樹來表示2-3樹的方法:將紅黑樹中左傾的紅連結水平放置,那麼紅連結所連線的兩節點就構成了2-3樹的3-節點,其他的構成2-節點。(結合下圖)

基本操作

節點表示Node

由於每一個節點僅有一個連結指向父節點,因此對此連結標色,以區別紅黑連結

private static final boolean RED = true;
private static final boolean BLACK = false;

private class Node{
    Key key;
    Value val;
    Node left, right;
    boolean color; // 父連結的標色
}

private boolean isRed(Node x){
    if (x == null) return false;
    return x.color == RED;
}

左旋left rotation

private Node rotateLeft(Node h){
    assert isRed(h.right);//判斷右連結是否紅,即是否右傾的情況
    Node x = h.right;
    h.right = x.left;
    x.left = h;
    x.color = h.color;
    h.color = RED;
    return x;
}

右旋right rotation

private Node rotateRight(Node h){
    assert isRed(h.left);//判斷左連結是否紅,即是否左傾的情況
    Node x = h.left;
    h.left = x.right;
    x.right = h;
    x.color = h.color;
    h.color = RED;
    return x;
}

跳色color flip

private void flipColors(Node h){
    assert !isRed(h);//判斷
    assert isRed(h.left);
    assert isRed(h.right);
    h.color = RED;
    h.left.color = BLACK;
    h.right.color = BLACK;
}

通過左旋、右旋、跳色等操作,可以保持紅黑樹的對稱有序絕對平衡的特點。

查詢

基於紅黑樹實現的BSTs的查詢操作與基本的BST的查詢操作是一致的。


public Val get(Key key){
    Node x = root;
    while (x != null){
        int cmp = key.compareTo(x.key);
        if (cmp < 0) x = x.left;
        else if (cmp > 0) x = x.right;
        else return x.val;
    }
    return null;
}

插入

當插入一個節點(節點C)到一棵紅黑樹中,為了保持絕對平衡和對稱有序的特點,存在以下情況:

插入的節本操作可以描述成:(結合下圖)

  • 基本的BST插入操作,同時新插入的節點的附連結標成紅色
  • 如果需要的話,左右旋轉去平衡4-節點(一個節點同時連線兩個紅連結)
  • 通過跳色操作將紅連結往上一層傳遞
  • 如果需要的話,旋轉以保持所有的紅連結左傾
  • 迴圈操作直到滿足紅黑樹的所有特徵

總結起來,在遞迴的場景下,就是以下三種情況:

  • 右連結紅,左連結黑:左旋
  • 左連結紅,左子節點的左連結紅:右旋
  • 左右連結紅:跳色
private Node put(Node h, Key key, Value val){

    if (h == null) return new Node(key, val, RED);//插入節點(遞迴出口)
    int cmp = key.compareTo(h.key);
    if (cmp < 0) h.left = put(h.left, key, val);
    else if (cmp > 0) h.right = put(h.right, key, val);
    else  h.val = val;

    if (isRed(h.right) && !isRed(h.left)) h = rotateLeft(h);
    if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h);
    if (isRed(h.left) && isRed(h.right)) flipColors(h);

    return h;
}

效能分析

通過紅黑樹實現的BST,其樹高在通常情況下 ~lgN,在最壞的情況下不超過 ~2lgN

應用

JAVA:java.util.TreeMap ,java.util.TreeSet等資料結構 C++ STL:map, mutilmap, mutilset等資料結構 linux核心

3. B樹

基本概念

B樹是2-3樹的泛化:在B樹中,每個節點允許有M-1個子節點(子連結)。(M的取值視實際情況而定) B樹的特徵如下:(結合下圖)

  • 跟節點至少有兩個子連結
  • 其他節點至少有M/2個子連結
  • 外部節點包含內部節點的key(葉節點就是外部節點)
  • 內部節點包含每個外部節點的首個key(用於索引)

基本操作

查詢

  • 從根節點開始
  • 通過內部節點對比key,確定對應的連結
  • 通過連結確定儲存key的外部節點

插入

  • 先查詢新key的位置
  • 插入
  • 如果溢位,則要分離節點,並將首key儲存在上一級的內部節點

應用

B樹被廣泛地應用在各作業系統的檔案系統和資料庫中。如windows的NTFS、Mac的HFS和SQL、ORACLE等各種主流資料庫。