前言
本人是算法小白,java寫得比較多,所以不說算法具體實現和列代碼,也沒那個實力,所以本文的出發點是,對算法不非常感冒的小白做個簡易了解。
參考:算法導論
關於二叉搜索樹
便於查找特定數據,按關鍵字大小構造的一棵二叉樹,紅黑樹和B-Tree都是二叉搜索樹的變形,所以二叉搜索樹很關鍵又很容易掌握。多說無益,直接給demo
這是用一個手機軟件畫的(看水印就知道了),很好用,在這里給它打個小廣告。
本文規約:
一個結點x,x.key代表x的關鍵字,x.left代表x的左孩子,x.right代表x的右孩子,x.p代表x的雙親(parent,或者叫父親)
特點(結構):
這是一棵二叉搜索樹,它的特點就是對於任意一個結點,其左子樹中最大關鍵字都不超過x.key,其右子樹中最小關鍵字都不小於x.key。這樣結構很容易聯想到二分法,二分法在一個有序序列找一個數效率是挺可觀的。
這個特點的好處:
在demo中,我們要找20,就從根結點40開始,40>20,所以我們去40的左孩子9,9<20,所以去9的右孩子,20==20,找到了。當然如果找不到就返回NULL或者NIL(算法書里面用來說明該結點是空的一個特殊結點),於是乎,很容易想象到二叉搜索樹的查找代碼就是一個簡單的遞歸。
缺點:
demo中如果細心就會發現這棵書的右邊很臃腫,二叉搜索樹的缺點便是在這里,這棵樹非常不平衡,或者說數據非常極端,偏向於某一邊,那么這個樹的查找效率就跟遍歷一個序列沒什么差別,所以紅黑樹的目的就是讓二叉搜索樹近似於平衡。
有序:
因為二叉搜索樹的特點,如果中序遍歷這棵樹,輸出的序列就是所有關鍵字的正向排序。可以試下中序遍歷demo,輸出就是3,6,9,13,20,40,50,65,73,90
插入和刪除:
插入:
插入比較簡單,跟查找類似,一直往下,比新結點z小就往左,比z大就往右,知道遇到NULL或者NIL,就掛在那個葉子結點上。插入一直是在后面樹的底插,所以二叉搜索樹的根結點就是第一個插入的結點,而且不能保證這棵樹是不是平衡
刪除:
刪除分三種情況:
- 刪除結點z沒有孩子結點,直接把z從父節點斷開,並用NULL或者NIL替換z
- 如果z只有一個孩子結點,把這個孩子結點代替z就可以了
- 如果z有兩個孩子,這時候略微麻煩,先說一下什么是后繼
后繼:一個結點x的后繼,就是關鍵字大於x.key的結點中最小的那個,注意這里有兩種情況,如果x是有右子樹,那就是x的右子樹中最小那個,也就是x的右子樹的最左那個結點;如果x是沒有右子樹,那就需要往上找,從x的父結點開始,一直往左上走(對的是左上方向),一直沒有路了,那終點的父節點就是x的后繼了。對於第二種情況我給個圖:
回到剛剛刪除的第三種情況,刪除結點z有兩個孩子,我們需要找到z的后繼y(一定會在z的右子樹( ̄▽ ̄) ,額好像上面白講了),用z的后繼y代替z,z的右子樹成為y的新的右子樹,z的左子樹稱為y的新的左子樹。這里直接上算法導論的圖