二叉查找樹

二叉查找樹定義

二叉查找樹(Binary Search Tree), 也稱為二叉搜索樹, 有序二叉樹(ordered binary tree), 排序二叉樹(sorted binary tree), 是指一顆空樹或具有以下性質的二叉樹:
1. 任意節(jié)點的左子樹不空, 則左子樹上所有節(jié)點的值均小于它的根節(jié)點的值
2. 任意節(jié)點的右子樹不空, 則右子樹上所有節(jié)點均大于它的根節(jié)點的值
3. 任意節(jié)點的左,右子樹也分別為二叉查找樹
4. 沒有鍵值相等的節(jié)點

二叉查找樹通常采用二叉鏈表作為二叉查找樹的存儲結構, 相比于其他數據結構的優(yōu)勢在于查找,插入時間復雜度較低, 為O(log n). 它是基礎的數據結構, 用于構建 紅黑數, B-Tree, B+Tree, B*Tree等.

二叉查找樹的Java實現
1. 二叉查找樹節(jié)點定義
public class BSTNode<T extends Comparable<T>> {
    T key;                // 關鍵字(鍵值)
    BSTNode<T> left;    // 左孩子
    BSTNode<T> right;    // 右孩子
    BSTNode<T> parent;    // 父結點

    public BSTNode(T key, BSTNode<T> parent, BSTNode<T> left, BSTNode<T> right) {
        this.key = key;
        this.parent = parent;
        this.left = left;
        this.right = right;
    }

    public T getKey() {
        return key;
    }

    public String toString() {
        return "key:"+key;
    }
}

BSTNode是二叉查找樹的內部節(jié)點, 它包含以下信息:

  1. key 對二叉樹進行排序的依據
  2. left 左邊子節(jié)點
  3. right 右邊子節(jié)點
  4. parent 當前節(jié)點的父節(jié)點
2. 二叉查找樹的查找
/*
 * (遞歸實現)查找"二叉樹x"中鍵值為key的節(jié)點
 */
private BSTNode<T> search(BSTNode<T> x, T key) {
    if (x==null)
        return x;

    int cmp = key.compareTo(x.key);
    if (cmp < 0)
        return search(x.left, key);
    else if (cmp > 0)
        return search(x.right, key);
    else
        return x;
}

public BSTNode<T> search(T key) {
    return search(mRoot, key);
}

search 的過程比較簡單, 從根節(jié)點開始, 根據給定的key與節(jié)點的key值進行比較, 直到 "cmp" = 0 或節(jié)點x = 0.

3. 查找最大值, 最小值

最大值

/*
 * 查找最大結點:返回tree為根結點的二叉樹的最大結點。
 */
private BSTNode<T> maximum(BSTNode<T> tree) {
    if (tree == null)
        return null;

    while(tree.right != null)
        tree = tree.right;
    return tree;
}

public T maximum() {
    BSTNode<T> p = maximum(mRoot);
    if (p != null)
        return p.key;

    return null;
}

最小值

/*
 * 查找最小結點:返回tree為根結點的二叉樹的最小結點。
 */
private BSTNode<T> minimum(BSTNode<T> tree) {
    if (tree == null)
        return null;

    while(tree.left != null)
        tree = tree.left;
    return tree;
}

public T minimum() {
    BSTNode<T> p = minimum(mRoot);
    if (p != null)
        return p.key;

    return null;
}
4. 查找前繼節(jié)點(predecessor) 后繼節(jié)點(successor)

查找前繼節(jié)點

/*
 * 找結點(x)的前繼結點芦缰。即谨敛,查找"二叉樹中數據值小于該結點"的"最大結點"辰斋。
 */
public BSTNode<T> predecessor(BSTNode<T> x) {
    // 如果x存在左孩子浪听,則"x的前繼結點"為 "以其左孩子為根的子樹的最大結點"院溺。
    if (x.left != null)
        return maximum(x.left);

    // 如果x沒有左孩子窒所。則x由分以下兩種情況討論:
    // (01) x是"一個右孩子"鹉勒,則"x的前驅結點"為 "它的父結點"。
    // (01) x是"一個左孩子"吵取,則查找"x的最低的父結點贸弥,并且x在該父結點右子樹上孩子或是其又子節(jié)點",找到的這個"最低的父結點"就是"x的前繼結點"海渊。
    BSTNode<T> y = x.parent;
    while ((y!=null) && (x==y.left)) {
        x = y;
        y = y.parent;
    }

    return y;
}

查找后繼節(jié)點

/*
 * 找結點(x)的后繼結點绵疲。即,查找"二叉樹中數據值大于該結點"的"最小結點"臣疑。
 */
public BSTNode<T> successor(BSTNode<T> x) {
    // 如果x存在右孩子盔憨,則"x的后繼結點"為 "以其右孩子為根的子樹的最小結點"。
    if (x.right != null)
        return minimum(x.right);

    // 如果x沒有右孩子讯沈。則x分以下兩種情況進行討論:
    // (01) x是"一個左孩子"郁岩,則"x的后繼結點"為 "它的父結點"。
    // (02) x是"一個右孩子"缺狠,則查找"x的最低的父結點问慎,并且x是該父結點左子樹上的孩子節(jié)點或直接是左子節(jié)點",找到的這個"最低的父結點"就是"x的后繼結點"挤茄。
    BSTNode<T> y = x.parent;
    while ((y!=null) && (x==y.right)) {
        x = y;
        y = y.parent;
    }

    return y;
}
5. 插入節(jié)點

/*
 * 將結點插入到二叉樹中
 *
 * 參數說明:
 *     tree 二叉樹的
 *     z 插入的結點
 */
private void insert(BSTree<T> bst, BSTNode<T> z) {
    int cmp;
    BSTNode<T> y = null;
    BSTNode<T> x = bst.mRoot;

    // 1. 查找z的插入位置
    while (x != null) {
        y = x;
        cmp = z.key.compareTo(x.key);
        if (cmp < 0)
            x = x.left;
        else
            x = x.right;
    }

    //2. 根據位置決定放在root節(jié)點, y的左/右邊
    z.parent = y;
    if (y==null) // y是null
        bst.mRoot = z;
    else {
        cmp = z.key.compareTo(y.key);
        if (cmp < 0)
            y.left = z;
        else
            y.right = z;
    }
}

/*
 * 新建結點(key)如叼,并將其插入到二叉樹中
 *
 * 參數說明:
 *     tree 二叉樹的根結點
 *     key 插入結點的鍵值
 */
public void insert(T key) {
    BSTNode<T> z=new BSTNode<T>(key,null,null,null);

    // 如果新建結點失敗,則返回穷劈。
    if (z != null)
        insert(this, z);
}
5. 刪除節(jié)點
/*
 * 刪除結點(z)笼恰,并返回被刪除的結點
 *
 * 參數說明:
 *     bst 二叉樹
 *     z 刪除的結點
 */
private BSTNode<T> remove(BSTree<T> bst, BSTNode<T> z) {
    BSTNode<T> x=null;
    BSTNode<T> y=null;
    /** 1. 待刪除節(jié)點情況
     * 1) 節(jié)點z最多一個子節(jié)點, 則刪除z后將對應子節(jié)點代替原來的位置
     * 2) 節(jié)點有兩個子節(jié)點, 調用 successor方法獲取其后繼節(jié)點, 后繼節(jié)點代替原來的那個節(jié)點
     */
    if ((z.left == null) || (z.right == null) )
        y = z; // 節(jié)點z最多有一個子節(jié)點
    else{
        // 這里有個知識點, 既然y是后繼節(jié)點, 則 y 必定沒有兩個子節(jié)點
        y = successor(z); // 節(jié)點z有兩個子節(jié)點, 則調用 successor 查詢z對應的子節(jié)點
    }

    // 2. 將待刪除節(jié)點的子節(jié)點賦值給x
    if (y.left != null)
        x = y.left;
    else
        x = y.right;
    /**
     * x 情況
     * 1. x是被刪除節(jié)點的子節(jié)點
     * 2. x是被刪除節(jié)點的后繼節(jié)點的子節(jié)點
     */
    if (x != null) {
        x.parent = y.parent;
    }

    // y.parent == null, 則說明y是mRoot節(jié)點
    if (y.parent == null)
        bst.mRoot = x;
    else if (y == y.parent.left)
        y.parent.left = x;
    else
        y.parent.right = x;

    // 若y是z的后繼節(jié)點
    if (y != z) {
        z.key = y.key;
    }

    return y;
}
6. 二叉查找樹完整實現代碼

二叉查找樹Java實現 BSTree.java

總結

二叉查找樹總體實現比較簡單, 但這是學習 RBTree, B-Tree, B+Tree 等數據結構的基礎

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末踊沸,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子社证,更是在濱河造成了極大的恐慌逼龟,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件追葡,死亡現場離奇詭異腺律,居然都是意外死亡,警方通過查閱死者的電腦和手機宜肉,發(fā)現死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門匀钧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人崖飘,你說我怎么就攤上這事榴捡。” “怎么了朱浴?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵吊圾,是天一觀的道長。 經常有香客問我翰蠢,道長项乒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任梁沧,我火速辦了婚禮檀何,結果婚禮上,老公的妹妹穿的比我還像新娘廷支。我一直安慰自己频鉴,他們只是感情好,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布恋拍。 她就那樣靜靜地躺著垛孔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪施敢。 梳的紋絲不亂的頭發(fā)上周荐,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機與錄音僵娃,去河邊找鬼概作。 笑死,一個胖子當著我的面吹牛默怨,可吹牛的內容都是我干的讯榕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼先壕,長吁一口氣:“原來是場噩夢啊……” “哼瘩扼!你這毒婦竟也來了谆甜?” 一聲冷哼從身側響起垃僚,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤集绰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谆棺,有當地人在樹林里發(fā)現了一具尸體栽燕,經...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年改淑,在試婚紗的時候發(fā)現自己被綠了碍岔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡朵夏,死狀恐怖蔼啦,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情仰猖,我是刑警寧澤捏肢,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站饥侵,受9級特大地震影響鸵赫,放射性物質發(fā)生泄漏。R本人自食惡果不足惜躏升,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一辩棒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧膨疏,春花似錦一睁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至双霍,卻和暖如春砚偶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背洒闸。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工染坯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丘逸。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓单鹿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親深纲。 傳聞我的和親對象是個殘疾皇子仲锄,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內容