BST --- Java版

一. 簡介

二叉查找樹(BST)是二叉樹的一個(gè)重要的應(yīng)用,它在二叉樹的基礎(chǔ)上加上了這樣的一個(gè)性質(zhì):對于樹中的每一個(gè)節(jié)點(diǎn)來說钞螟,如果有左兒子的話,它的左兒子的值一定小于它本身的值谎碍,如果有右兒子的話鳞滨,它的右兒子的值一定大于它本身的值。
??我用一句話概括:左 < 中 < 右椿浓。 根據(jù)這個(gè)原理太援,我們可以推斷:BST的中序遍歷必定是嚴(yán)格遞增的

二. 數(shù)據(jù)結(jié)構(gòu)

public class BST<T extends Comparable<T>> {
    class Node {
        private T data;
        private Node left;
        private Node right;
        private int N;

        public Node(T data, int N) {
            this.data = data;
            this.N = N;
            this.left = null;
            this.right = null;
        }
    }

    private Node root;

    public int size() {
        return size(root);
    }

    private int size(Node n) {
        if (n == null) return 0;
        else return n.N;
    }

    public void put(T x) {
        root = put(root, x);
    }

    public Node min() {
        return min(root);
    }

    private Node min(Node n) {
        if (n == null)
            return null;
        while (n.left != null) {
            n = n.left;
        }
        return n;
    }

    private Node put(Node n, T x) {
        if (n == null) return new Node(x, 1);  //樹為空
        int cmp = x.compareTo(n.data);
        if (cmp < 0) {
            n.left = put(n.left, x);
        } else if (cmp > 0) {
            n.right = put(n.right, x);
        } else n.data = x;
        n.N = 1 + size(n.left) + size(n.right);
        return n;
    }

    public void delete(T x) {
        if (x == null) throw new IllegalArgumentException("called delete() with a null key");
        root = delete(root, x);
    }

    private Node delete(Node n, T x) {
        if (n == null) return null;
        int cmp = x.compareTo(n.data);
        if (cmp < 0) {
            n.left = delete(n.left, x);
        } else if (cmp > 0) {

        } else {  //如果相等,此節(jié)點(diǎn)就是要?jiǎng)h除的節(jié)點(diǎn)
            if (n.left == null)
                return n.right;     // 這里return扳碍,相當(dāng)于把當(dāng)前節(jié)點(diǎn)的直接右節(jié)點(diǎn)連到當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)
            if (n.right == null)
                return n.left;      // 這里return提岔,相當(dāng)于把當(dāng)前節(jié)點(diǎn)的直接左節(jié)點(diǎn)連到當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)
            // 有2個(gè)孩子
            Node t = n;
            n = min(t.right);       // t的右子樹最小的節(jié)點(diǎn)替換這個(gè)被刪除的節(jié)點(diǎn)
            n.right = deleteMin(t.right);
            n.left = t.left;
        }
        n.N = size(n.left) + size(n.right) + 1;
        return n;
    }

    private Node deleteMin(Node n) {
        if (n.left == null) return n.right;
        n.left = deleteMin(n.left);
        n.N = size(n.left) + size(n.right) + 1;
        return n;
    }
}

  1. 插入:
    ??根據(jù)二叉查找樹的性質(zhì),插入一個(gè)節(jié)點(diǎn)的時(shí)候笋敞,如果根節(jié)點(diǎn)為空碱蒙,就此節(jié)點(diǎn)作為根節(jié)點(diǎn),如果根節(jié)點(diǎn)不為空夯巷,就要先和根節(jié)點(diǎn)比較赛惩,如果比根節(jié)點(diǎn)的值小,就插入到根節(jié)點(diǎn)的左子樹中趁餐,如果比根節(jié)點(diǎn)的值大就插入到根節(jié)點(diǎn)的右子樹中喷兼,如此遞歸下去,找到插入的位置后雷。重復(fù)節(jié)點(diǎn)用新值更新季惯。如圖1是一個(gè)插入的過程。
圖1.png
  1. 查找:
    ??查找的功能和插入差不多一樣臀突,按照插入那樣的方式遞歸下去勉抓,如果找到了,就返回這個(gè)節(jié)點(diǎn)的地址候学,如果沒有找到藕筋,就返回null。

3.刪除:
??1?? 首先先實(shí)現(xiàn)刪除這個(gè)樹中最小的元素: Node deleteMin(Node n){}函數(shù).
思路是:

  • 一直找節(jié)點(diǎn)Node的左子樹梳码,直到找到當(dāng)前節(jié)點(diǎn)的左兒子為空(n.left == null,)
  • 用找到的這個(gè)節(jié)點(diǎn)n的右兒子來替代它自己隐圾,這個(gè)節(jié)點(diǎn)n會沒有引用被gc掉
  • 更新節(jié)點(diǎn)數(shù)目
圖2.png

2?? 然后刪除某個(gè)節(jié)點(diǎn):
??如果是葉子節(jié)點(diǎn)的話伍掀,直接刪除就可以了。比如圖3翎承,要?jiǎng)h除的是C節(jié)點(diǎn)硕盹,它是葉子節(jié)點(diǎn)符匾,那么很簡單把它父節(jié)點(diǎn)的引用置為null叨咖。

圖3.png

??如果只有一個(gè)孩子的話,就讓它的父親指向它的兒子啊胶,然后刪除這個(gè)節(jié)點(diǎn)甸各。如下圖:

圖4.png

刪除有兩個(gè)兒子的節(jié)點(diǎn)會比較復(fù)雜一些。一般的刪除策略是用其右子樹最小的數(shù)據(jù)代替該節(jié)點(diǎn)的數(shù)據(jù)并遞歸的刪除掉右子樹中最小數(shù)據(jù)的節(jié)點(diǎn)焰坪。因?yàn)橛易訕渲袛?shù)據(jù)最小的節(jié)點(diǎn)肯定沒有左兒子趣倾,所以刪除的時(shí)候容易一些。(比如刪除下圖的E節(jié)點(diǎn)某饰,那么會找到E節(jié)點(diǎn)右子樹中最小的節(jié)點(diǎn)來替代節(jié)點(diǎn)E儒恋,如圖是H節(jié)點(diǎn), 當(dāng)H代替完E節(jié)點(diǎn),接下來調(diào)用deleteMin(E節(jié)點(diǎn))刪除H節(jié)點(diǎn))

圖5.png

三. 復(fù)雜度

平均復(fù)雜度 最壞情況復(fù)雜度

  • 插入操作 O(logN) ??O(N)

  • 查詢操作 O(logN) ??O(N)

  • 刪除操作 O(logN) ??O(N)

如果BST不是平衡的樹黔漂,如下圖退化成list诫尽,那么最大復(fù)雜度O(N)。如插入有序序列(1, 2, 3, 4, 5)炬守,插入操作完成后的BST如下圖:

圖6.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末牧嫉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子减途,更是在濱河造成了極大的恐慌酣藻,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鳍置,死亡現(xiàn)場離奇詭異辽剧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)税产,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門怕轿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人砖第,你說我怎么就攤上這事撤卢。” “怎么了梧兼?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵放吩,是天一觀的道長。 經(jīng)常有香客問我羽杰,道長渡紫,這世上最難降的妖魔是什么到推? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮惕澎,結(jié)果婚禮上莉测,老公的妹妹穿的比我還像新娘。我一直安慰自己唧喉,他們只是感情好捣卤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著八孝,像睡著了一般董朝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上干跛,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天子姜,我揣著相機(jī)與錄音,去河邊找鬼楼入。 笑死哥捕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嘉熊。 我是一名探鬼主播遥赚,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼记舆!你這毒婦竟也來了鸽捻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤泽腮,失蹤者是張志新(化名)和其女友劉穎御蒲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诊赊,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厚满,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了碧磅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碘箍。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鲸郊,靈堂內(nèi)的尸體忽然破棺而出丰榴,到底是詐尸還是另有隱情,我是刑警寧澤秆撮,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布四濒,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盗蟆。R本人自食惡果不足惜戈二,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喳资。 院中可真熱鬧觉吭,春花似錦、人聲如沸仆邓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宏赘。三九已至绒北,卻和暖如春黎侈,著一層夾襖步出監(jiān)牢的瞬間察署,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工峻汉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贴汪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓休吠,卻偏偏與公主長得像扳埂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子瘤礁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 紅黑樹是平衡二叉查找樹的一種阳懂。為了深入理解紅黑樹,我們需要從二叉查找樹開始講起柜思。 BST 二叉查找樹(Binary...
    kanehe閱讀 1,375評論 0 8
  • 樹的概述 樹是一種非常常用的數(shù)據(jù)結(jié)構(gòu)岩调,樹與前面介紹的線性表,棧赡盘,隊(duì)列等線性結(jié)構(gòu)不同号枕,樹是一種非線性結(jié)構(gòu) 1.樹的定...
    Jack921閱讀 4,455評論 1 31
  • 以前喜歡把自己的思緒傾泄于筆端,覺得這是一種放松自己心情的好的方式陨享。但是近來卻越發(fā)沒有這種心思了葱淳,更多的時(shí)候是心情...
    小城幽篁閱讀 269評論 0 0
  • 你討厭爸爸,沒有責(zé)任感抛姑,自私赞厕,短視,懦弱自卑定硝,還喜歡大男子主義…… 你討厭下屬皿桑,不只知,自大無腦,離譜唁毒,消極蒜茴,……...
    吾空空閱讀 205評論 0 0
  • 我也不知道要寫什么粉私。先寫起來。只是篤信寫作的重要近零,所以打起鍵盤寫了诺核。還有個(gè)原因,我的一個(gè)微信群要求周二主題討論久信,我...
    wendy_zo閱讀 152評論 0 0