二叉查找樹

什么是二叉查找樹腾务?

二叉查找樹又名二叉排序樹捂龄、二叉搜索樹揩慕,具有如下性質(zhì):

  1. 若左子樹不為空漆诽,則左子樹上的所有節(jié)點(diǎn)的值均小于它的根節(jié)點(diǎn)上的值
  2. 若右子樹不為空侮攀,則右子樹上的所有節(jié)點(diǎn)的值均大于它的根節(jié)點(diǎn)上的值
  3. 左、右子樹也分別都為二叉查找樹
  4. 沒有鍵值相等的兩個(gè)節(jié)點(diǎn)

二叉查找樹的優(yōu)缺點(diǎn)

1. 查找性能
查找過程:從根節(jié)點(diǎn)出發(fā)厢拭,若根節(jié)點(diǎn)的關(guān)鍵字等于要查找的值兰英,則查找完成;如果小于根節(jié)點(diǎn)的值供鸠,則遞歸查找左子樹畦贸;否則遞歸查找右子樹。如果到葉子節(jié)點(diǎn)楞捂,還沒有查找到家制,則說明這個(gè)樹中沒有這個(gè)值。

  • 當(dāng)二叉樹中每個(gè)節(jié)點(diǎn)左右子樹的高度大致相同泡一,則樹的高度為logN颤殴。則平均時(shí)間復(fù)雜度也就為O(logN)
  • 當(dāng)二叉樹插入節(jié)點(diǎn)時(shí),關(guān)鍵字本來就有序鼻忠,二叉樹就會(huì)形成一個(gè)單支樹結(jié)構(gòu)涵但,查找也就變得和順序查找一模一樣了杈绸。這時(shí)的查找效率最低為0(n)

2. 插入性能
因?yàn)樾鹿?jié)點(diǎn)插入到樹中的葉子節(jié)點(diǎn)上的,所以插入一個(gè)節(jié)點(diǎn)和查找一個(gè)不存在的值的代價(jià)是一樣的矮瘟。

3. 刪除性能
首先找到這個(gè)要?jiǎng)h除的節(jié)點(diǎn)p瞳脓,代價(jià)和查找這個(gè)值一樣。然后需要改變樹的結(jié)構(gòu)澈侠。如果左右子樹都為空弄痹,則直接刪除這個(gè)葉子節(jié)點(diǎn)灸撰;

1.png

如果這個(gè)刪除節(jié)點(diǎn)的左右子樹只存在一個(gè)槽地,那么直接把左節(jié)點(diǎn)或右節(jié)點(diǎn)的父親設(shè)置為p的父親即可斟珊;

2.png

如果左右子樹都存在,則把右子樹中值最小的節(jié)點(diǎn)找到拳球,交換到要?jiǎng)h除節(jié)點(diǎn)的位置审姓,然后調(diào)整下子樹即可。

3.png

python實(shí)現(xiàn)二叉查找樹

#!/usr/bin/python
# encoding: utf-8

class BinarySearchTree(object):
    # 每個(gè)節(jié)點(diǎn)的結(jié)構(gòu)祝峻,left和right的值代表左右子節(jié)點(diǎn)魔吐,value為當(dāng)前節(jié)點(diǎn)關(guān)鍵字的值
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

    # 插入一個(gè)節(jié)點(diǎn)
    def insert(self, x):
        if x < self.value:
            if self.left:
                self.left.insert(x)
            else:
                self.left = BinarySearchTree(x)
        elif x > self.value:
            if self.right:
                self.right.insert(x)
            else:
                self.right = BinarySearchTree(x)

    # 遍歷二叉樹查找一個(gè)值
    def find(self, x, parent=None):
        if x == self.value:
            return self, parent
        elif x < self.value and self.left:
            return self.left.find(x, self)
        elif x > self.value and self.right:
            return self.right.find(x, self)
        else:
            return None, None

    # 關(guān)鍵值最小的節(jié)點(diǎn)
    def findMin(self):
        if self.left:
            return self.left.findMin()
        else:
            return self

    # 關(guān)鍵值最大的節(jié)點(diǎn)
    def findMax(self):
        if self.right:
            return self.right.findMax()
        else:
            return self

    # 刪除一個(gè)節(jié)點(diǎn)
    def delete(self, x):
        node, parent = self.find(x);
        # 如果有這個(gè)值才進(jìn)行刪除操作
        if node is not None:
            # 如果該節(jié)點(diǎn)下沒有子節(jié)點(diǎn)
            if not node.left and not node.right:
                if parent.left is node:
                    parent.left = None
                else:
                    parent.right = None
                del node
            # 只有一個(gè)子節(jié)點(diǎn)時(shí),則讓這個(gè)子節(jié)點(diǎn)替換這個(gè)要?jiǎng)h除的節(jié)點(diǎn)
            elif (not node.left and node.right) or (node.left and not node.right):
                if node.left:
                    n = node.left
                else:
                    n = node.right
                if parent:
                    if parent.left is node:
                        parent.left = n
                    else:
                        parent.right = n
                del node
            # 刪除節(jié)點(diǎn)有左子節(jié)點(diǎn)莱找,也有右子節(jié)點(diǎn)酬姆。
            else:
                parent = node
                successor = node.right
                while successor.left:
                    parent = successor
                    successor = successor.left
                # 找到右子樹中最小的值后賦值給要?jiǎng)h除的節(jié)點(diǎn)
                node.value = successor.value
                # 左右子樹微調(diào)
                if parent.left == successor:
                    parent.left = successor.right
                else:
                    parent.right = successor.right
                del successor

    # 按照順序打印
    def printTree(self):
        if self.left:
            self.left.printTree()
        print self.value,
        if self.right:
            self.right.printTree()


if __name__ == '__main__':
    root = BinarySearchTree(10)
    root.insert(6)
    root.insert(5)
    root.insert(8)
    root.insert(7)
    root.insert(9)
    root.printTree()
    print ''  # 另起一行
    x, y = root.find(9)
    print x.value, y.value  # 打印查explorer.exe找的值和其父親的值
    print root.findMax().value, root.findMin().value  # 打印最小值和最大值
    root.delete(5)
    root.printTree()

執(zhí)行結(jié)果

5 6 7 8 9 10 
9 8
10 5
6 7 8 9 10
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市奥溺,隨后出現(xiàn)的幾起案子轴踱,更是在濱河造成了極大的恐慌,老刑警劉巖谚赎,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異诱篷,居然都是意外死亡壶唤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門棕所,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闸盔,“玉大人,你說我怎么就攤上這事琳省∮常” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵针贬,是天一觀的道長(zhǎng)击费。 經(jīng)常有香客問我,道長(zhǎng)桦他,這世上最難降的妖魔是什么蔫巩? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上圆仔,老公的妹妹穿的比我還像新娘垃瞧。我一直安慰自己,他們只是感情好坪郭,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布个从。 她就那樣靜靜地躺著,像睡著了一般歪沃。 火紅的嫁衣襯著肌膚如雪嗦锐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天绸罗,我揣著相機(jī)與錄音意推,去河邊找鬼。 笑死珊蟀,一個(gè)胖子當(dāng)著我的面吹牛菊值,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播育灸,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼腻窒,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了磅崭?” 一聲冷哼從身側(cè)響起儿子,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎砸喻,沒想到半個(gè)月后柔逼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡割岛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年愉适,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片癣漆。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡维咸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惠爽,到底是詐尸還是另有隱情癌蓖,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布婚肆,位于F島的核電站租副,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏较性。R本人自食惡果不足惜附井,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一讨越、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧永毅,春花似錦把跨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至意蛀,卻和暖如春耸别,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背县钥。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工秀姐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人若贮。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓省有,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親谴麦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蠢沿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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