java 二叉树特点_疯狂java笔记之树和二叉树
樹(shù)的概述
樹(shù)是一種非常常用的數(shù)據(jù)結(jié)構(gòu),樹(shù)與前面介紹的線性表,棧,隊(duì)列等線性結(jié)構(gòu)不同,樹(shù)是一種非線性結(jié)構(gòu)
1.樹(shù)的定義和基本術(shù)語(yǔ)
計(jì)算機(jī)世界里的樹(shù),是從自然界中實(shí)際的樹(shù)抽象而來(lái)的,它指的是N個(gè)有父子關(guān)系的節(jié)點(diǎn)的有限集合。對(duì)于這個(gè)有限的節(jié)點(diǎn)集合而言,它滿足如下條件:
當(dāng)N=0時(shí),改節(jié)點(diǎn)集合為空,這課樹(shù)也被稱為空樹(shù)
在任意的非空樹(shù)中,有且僅有一個(gè)根(root)節(jié)點(diǎn)
當(dāng)N>1時(shí),除根節(jié)點(diǎn)以外的其余節(jié)點(diǎn)可分為M個(gè)互為相交的有限集合T1,T2,...,Tm,其中的每個(gè)集合本身又是一棵樹(shù),并稱其為根的子樹(shù)(subtree)。
從上面定義可以發(fā)現(xiàn)樹(shù)的遞歸特性:一棵樹(shù)由根和若干棵子樹(shù)組成,而每棵子樹(shù)又由若干棵更小的子樹(shù)組成。
樹(shù)中任一節(jié)點(diǎn)可以有0或多個(gè)子節(jié)點(diǎn),但只能有一個(gè)父節(jié)點(diǎn)。根節(jié)點(diǎn)是一個(gè)特例,根節(jié)點(diǎn)沒(méi)有父節(jié)點(diǎn),葉子節(jié)點(diǎn)沒(méi)有子節(jié)點(diǎn)。樹(shù)中每個(gè)節(jié)點(diǎn)既可以是其上一級(jí)節(jié)點(diǎn)的子節(jié)點(diǎn),也可以是下一級(jí)節(jié)點(diǎn)的父節(jié)點(diǎn),因此同一個(gè)節(jié)點(diǎn)既可以是父節(jié)點(diǎn),也可以是子節(jié)點(diǎn)(類似于一個(gè)人—————他既是他兒子的父親,又是他父親的兒子)。
很顯然,父子關(guān)系是一種非線性關(guān)系,所以樹(shù)結(jié)構(gòu)是非線性結(jié)構(gòu)。
如果按節(jié)點(diǎn)是否包含子節(jié)點(diǎn)來(lái)分,節(jié)點(diǎn)可以分成以下兩種:
普通節(jié)點(diǎn):包含子節(jié)點(diǎn)的節(jié)點(diǎn)
葉子節(jié)點(diǎn):沒(méi)有子節(jié)點(diǎn)的節(jié)點(diǎn),因此葉子節(jié)點(diǎn)不可作為父節(jié)點(diǎn)
如果按節(jié)點(diǎn)是否具有唯一的父節(jié)點(diǎn)來(lái)分,節(jié)點(diǎn)有可分為如下兩種:
根節(jié)點(diǎn):沒(méi)有父節(jié)點(diǎn)的節(jié)點(diǎn),根節(jié)點(diǎn)不可作為子節(jié)點(diǎn)
普通節(jié)點(diǎn):具有唯一父節(jié)點(diǎn)的節(jié)點(diǎn)
一棵樹(shù)只能有一個(gè)根節(jié)點(diǎn),如果一棵樹(shù)有了多個(gè)根節(jié)點(diǎn),那么它已經(jīng)不再是一棵樹(shù)了,而是多棵樹(shù)的集合,有時(shí)也被稱為森林。示意圖如下:
tree.PNG
與樹(shù)有關(guān)的術(shù)語(yǔ)有如下一些:
節(jié)點(diǎn):樹(shù)的最基本組成單元,通常包括一個(gè)數(shù)據(jù)元素及若干指針用于指向其他節(jié)點(diǎn)。
節(jié)點(diǎn)的度:節(jié)點(diǎn)擁有的子樹(shù)的個(gè)數(shù)被稱為節(jié)點(diǎn)的度(degree)
樹(shù)的度:樹(shù)中所有節(jié)點(diǎn)的度的最大值就是該樹(shù)的度
葉子節(jié)點(diǎn):度為0的節(jié)點(diǎn)被稱為葉子節(jié)點(diǎn)或終端節(jié)點(diǎn)
分支節(jié)點(diǎn):度不為0的節(jié)點(diǎn)被稱為分支節(jié)點(diǎn)或非終端節(jié)點(diǎn)
子節(jié)點(diǎn),父節(jié)點(diǎn),兄弟節(jié)點(diǎn):節(jié)點(diǎn)的子樹(shù)的根被稱為該節(jié)點(diǎn)的子節(jié)點(diǎn),而該節(jié)點(diǎn)稱為子節(jié)點(diǎn)的父節(jié)點(diǎn)(parent).具有相同父節(jié)點(diǎn)的子節(jié)點(diǎn)之間互稱為兄弟節(jié)點(diǎn)。
節(jié)點(diǎn)的層次(level):節(jié)點(diǎn)的層次從根開(kāi)始算起,根的層次值為1,其余節(jié)點(diǎn)的層次值為父節(jié)點(diǎn)層次值加l。
樹(shù)的深度(depth):樹(shù)中節(jié)點(diǎn)的最大層次值稱為樹(shù)的深度或高度。
有序樹(shù)與無(wú)序樹(shù):如果將樹(shù)中節(jié)點(diǎn)的各棵子樹(shù)看成從左到右是有序的(即不能互換),則稱該樹(shù)為有序樹(shù),否則稱為無(wú)序樹(shù)。
祖先節(jié)點(diǎn)(ancestor):從根到該節(jié)點(diǎn)所經(jīng)分支上的所有節(jié)點(diǎn)
后代節(jié)點(diǎn)(descendant):以某節(jié)點(diǎn)為根的子樹(shù)中任一節(jié)點(diǎn)都稱為該節(jié)點(diǎn)的后代節(jié)點(diǎn)。
森林(forest):森林是;兩顆或兩顆以上互不相交的樹(shù)的集合,刪去一棵樹(shù)的根,就得到一個(gè)森林。
樹(shù)的基本操作
如果需要實(shí)現(xiàn)一棵樹(shù),程序不僅要以合適的方式保存該樹(shù)的所有節(jié)點(diǎn),還要記錄節(jié)點(diǎn)與節(jié)點(diǎn)之間的父子關(guān)系。接下來(lái),還應(yīng)該為樹(shù)實(shí)現(xiàn)如下基本操作。
初始化:通常是一個(gè)構(gòu)造器,用于創(chuàng)建一棵空樹(shù),或者以指定節(jié)點(diǎn)為根來(lái)創(chuàng)建樹(shù)。
為指定節(jié)點(diǎn)添加子節(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))的第i個(gè)子節(jié)點(diǎn)
返回該樹(shù)的深度
返回指定節(jié)點(diǎn)的位置
為了實(shí)現(xiàn)樹(shù)這種數(shù)據(jù)結(jié)構(gòu),程序必須能記錄節(jié)點(diǎn)與節(jié)點(diǎn)之間的父子關(guān)系,為此有一下兩種選擇:
父節(jié)點(diǎn)表示法:每個(gè)子節(jié)點(diǎn)都記錄它的父節(jié)點(diǎn)。
子節(jié)點(diǎn)鏈表示法:每個(gè)非葉子節(jié)點(diǎn)通過(guò)一個(gè)鏈表來(lái)記錄它所有的子節(jié)點(diǎn)。
父節(jié)點(diǎn)表示法
通過(guò)前面的介紹可以發(fā)現(xiàn),樹(shù)中除根節(jié)點(diǎn)之外的每個(gè)節(jié)點(diǎn)都有一個(gè)父節(jié)點(diǎn)。為了記錄樹(shù)中節(jié)點(diǎn)與節(jié)點(diǎn)之間的父子關(guān)系,可以為每個(gè)節(jié)點(diǎn)增加一個(gè)parent域,用以記錄該節(jié)點(diǎn)的父節(jié)點(diǎn)。用如下圖和如下表來(lái)表示
tree_show.PNG
數(shù)組索引
data
parent
0
A
-1
1
B
0
2
C
0
3
D
0
4
E
1
5
F
3
6
G
3
7
H
4
8
I
4
9
J
4
10
K
6
...
...
...
由此可見(jiàn),只要用一個(gè)節(jié)點(diǎn)數(shù)組來(lái)保存樹(shù)里的每個(gè)節(jié)點(diǎn),并讓每個(gè)節(jié)點(diǎn)記錄其父節(jié)點(diǎn)在數(shù)組中的索引即可。
子節(jié)點(diǎn)鏈表表示法
父節(jié)點(diǎn)表示法的思想是讓每個(gè)節(jié)點(diǎn)“記住”它的父節(jié)點(diǎn)的索引,父節(jié)點(diǎn)表示法是從子節(jié)點(diǎn)著手的;反過(guò)來(lái),還有另外一種方式:讓父節(jié)點(diǎn)“記住”它的所有子節(jié)點(diǎn)口在這種方式下,由于每個(gè)父節(jié)點(diǎn)需要記住多個(gè)子節(jié)點(diǎn),因此必須采用“子節(jié)點(diǎn)鏈”表示法。示意圖如下:
tree_linked.PNG
二叉樹(shù)
二叉樹(shù)的定義和基本概念
二叉樹(shù)指的是每個(gè)節(jié)點(diǎn)最多只能有兩個(gè)子樹(shù)的有序樹(shù)。通常左邊的子樹(shù)被稱作“左子樹(shù)”(left subtree),右邊的子樹(shù)被稱為“右子樹(shù)”(right subtree).由此可見(jiàn),二叉樹(shù)依然是樹(shù),它是一種特殊的樹(shù)。
二叉樹(shù)的每個(gè)節(jié)點(diǎn)最多只有來(lái)兩顆樹(shù)(不存在度大于2的節(jié)點(diǎn)),二叉樹(shù)的子樹(shù)有左,右之分,次序不能顛倒。
樹(shù)和二叉樹(shù)的兩個(gè)重要區(qū)別如下:
樹(shù)中節(jié)點(diǎn)的最大度數(shù)沒(méi)有限制,而二叉樹(shù)節(jié)點(diǎn)的最大度數(shù)為2,也就是說(shuō),二叉樹(shù)是節(jié)點(diǎn)的最大度數(shù)為2的樹(shù)。
無(wú)序樹(shù)的節(jié)點(diǎn)無(wú)左右之分,而二叉樹(shù)的節(jié)點(diǎn)有左,右之分,也就是說(shuō),二叉樹(shù)是有序樹(shù)。
一棵深度為k的二叉樹(shù),如果它包含了
2^k-1
個(gè)節(jié)點(diǎn),就把這棵二叉樹(shù)稱為滿二叉樹(shù)。滿二叉樹(shù)的特點(diǎn)是。每一層上的節(jié)點(diǎn)數(shù)都是最大節(jié)點(diǎn)數(shù),即各層節(jié)點(diǎn)數(shù)分別為1,2,4,8, 16,...,滿二叉樹(shù)下圖所示:
two_tree.PNG
一顆有n個(gè)節(jié)點(diǎn)的二叉樹(shù),按滿二叉樹(shù)的編號(hào)方式對(duì)它進(jìn)行編號(hào),若樹(shù)中所有節(jié)點(diǎn)和滿二叉樹(shù)1~n編號(hào)完全一致,則稱該樹(shù)為完全二叉樹(shù)。也就是說(shuō),如果一顆二叉樹(shù)除最后一層外,其余層的所有節(jié)點(diǎn)都是滿的,并且最后一層或者是滿的,或者僅在右邊缺少若干連續(xù)的節(jié)點(diǎn),則此二叉樹(shù)就是完全二叉樹(shù)。
綜上所述,二叉樹(shù)大致有如下幾個(gè)性質(zhì):
二叉樹(shù)第i層上的節(jié)點(diǎn)數(shù)據(jù)至多為2的i-1次方
深度為k的二叉樹(shù)至多有2的k次方-1個(gè)節(jié)點(diǎn).滿二叉樹(shù)的每層節(jié)點(diǎn)的數(shù)量依次為1, 2, 4,8,…,因此深度為k的滿二叉樹(shù)包含的節(jié)點(diǎn)數(shù)為公比為2的等比數(shù)列的前k項(xiàng)總和,
即2的k次方一1。
在任何一棵二叉樹(shù)中,如果其葉子節(jié)點(diǎn)的數(shù)量為n0,度為2的子節(jié)點(diǎn)數(shù)量為n2,則
n0=n2 + 1。這是因?yàn)?如果為任意葉子節(jié)點(diǎn)增加一個(gè)子節(jié)點(diǎn),則原有葉子節(jié)點(diǎn)變成非葉子節(jié)點(diǎn),新增節(jié)點(diǎn)變成葉子節(jié)點(diǎn),上述等式不變;如果為任意葉子節(jié)點(diǎn)增加兩個(gè)子節(jié)點(diǎn),則原有葉子節(jié)點(diǎn)變成度為2的非葉子lto點(diǎn),新增的兩個(gè)節(jié)點(diǎn)變成葉子節(jié)點(diǎn),上述等式依然不變。
具有n個(gè)節(jié)點(diǎn)的完全二叉樹(shù)的深度為log2(n+1)
對(duì)于一顆具有n個(gè)節(jié)點(diǎn)的完全二叉樹(shù)的節(jié)點(diǎn)按層自左向右編號(hào),則對(duì)任一編號(hào)為i(n>=i>=1)的節(jié)點(diǎn)有下列性質(zhì)。
當(dāng)i==1時(shí),節(jié)點(diǎn)i是二叉樹(shù)的根;若i>1,則節(jié)點(diǎn)的父節(jié)點(diǎn)是i/2
若2i
若2i+1<=n,則節(jié)點(diǎn)i有右孩子,右孩子的編號(hào)是2i+1;否則,節(jié)點(diǎn)無(wú)右孩子。
1~n/2范圍的節(jié)點(diǎn)都是有孩子節(jié)點(diǎn)的非葉子節(jié)點(diǎn),其余的節(jié)點(diǎn)全部都是葉子節(jié)點(diǎn)。編號(hào)為n/2的節(jié)點(diǎn)可能只有左子節(jié)點(diǎn),也可能即有左子節(jié)點(diǎn),又有右子節(jié)點(diǎn)。
二叉樹(shù)的基本操作
二叉樹(shù)記錄其節(jié)點(diǎn)之間的父子關(guān)系更加簡(jiǎn)單,因?yàn)槎鏄?shù)中的每個(gè)節(jié)點(diǎn)最多只能保存兩個(gè)子節(jié)點(diǎn)。接下來(lái),程序也需要為二叉樹(shù)實(shí)現(xiàn)如下基本操作。
初始化:通常是一個(gè)構(gòu)造器,用于創(chuàng)建一顆空樹(shù),或者以指定節(jié)點(diǎn)為根來(lái)創(chuàng)建二叉樹(shù)。
為指定節(jié)點(diǎn)添加子節(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))的右子節(jié)點(diǎn)
返回該二叉樹(shù)的深度
返回指定節(jié)點(diǎn)的位置
要實(shí)現(xiàn)二叉樹(shù)這種數(shù)據(jù)結(jié)構(gòu),有以下三種選擇。
順序存儲(chǔ):采用數(shù)組來(lái)記錄二叉樹(shù)的所有節(jié)點(diǎn)。
二叉鏈表存儲(chǔ):每個(gè)節(jié)點(diǎn)保留一個(gè)left,right域,分別指向其左、右子節(jié)點(diǎn)。
三叉鏈表存儲(chǔ):每個(gè)節(jié)點(diǎn)保留一個(gè)left, right,parent域,分別指向其左、右子節(jié)點(diǎn)和父節(jié)點(diǎn)。
二叉樹(shù)的順序存儲(chǔ)
順序存儲(chǔ)指的是充分利用滿二叉樹(shù)的特性:每層的節(jié)點(diǎn)數(shù)分別為1, 2, 4, 8,…,2的(i-1)2的i次方。一棵
深度為i的二叉樹(shù)最多只能包含2的i次方一1個(gè)節(jié)點(diǎn),因此只要定義一個(gè)長(zhǎng)度為2的i次方一1的數(shù)組即可存儲(chǔ)這棵二叉樹(shù)。
對(duì)于普通二叉樹(shù)(不是滿二叉樹(shù)),那些空出來(lái)的節(jié)點(diǎn)對(duì)應(yīng)的數(shù)組元素留空就可以了。由此可見(jiàn),二叉樹(shù)采用順序存儲(chǔ)會(huì)造成一定的空間浪費(fèi)。對(duì)于下圖1所示的二叉樹(shù)(完全二叉樹(shù)),采用下圖2所示的數(shù)組來(lái)保存即可。
圖1.PNG
圖2.PNG
對(duì)于左圖所示的二叉樹(shù),需使用右圖所示的數(shù)組來(lái)保存。
compare_tree.PNG
當(dāng)使用數(shù)組來(lái)存儲(chǔ)二又樹(shù)的所有節(jié)點(diǎn)時(shí)可能會(huì)產(chǎn)生一定的空間浪費(fèi),如果該二叉樹(shù)是完全二叉樹(shù),就不會(huì)有任何空間浪費(fèi)了;但如果該二叉樹(shù)的所有節(jié)點(diǎn)都只有右子節(jié)點(diǎn),那么就會(huì)產(chǎn)生相當(dāng)大的空間浪費(fèi).
二叉樹(shù)的二叉鏈表存儲(chǔ)
二叉鏈表存儲(chǔ)的思想是讓每個(gè)節(jié)點(diǎn)都能“記住”它的左,右兩個(gè)子節(jié)點(diǎn)。為每個(gè)節(jié)點(diǎn)增加left,right兩個(gè)指針,分別引用改節(jié)點(diǎn)的左,右兩個(gè)子節(jié)點(diǎn),因此二叉鏈表存儲(chǔ)的每個(gè)節(jié)點(diǎn)有如下圖結(jié)構(gòu):
two_fork_tree.PNG
二叉鏈表存儲(chǔ)的二叉樹(shù)的節(jié)點(diǎn)大致有如下定義:
class Node{
Object data;
Node left;
Node right;
}
對(duì)于這種二叉鏈表存儲(chǔ)的二叉樹(shù),如果程序需要,為指定節(jié)點(diǎn)添加子節(jié)點(diǎn)也非常容易,讓父節(jié)點(diǎn)的left或right引用指向新節(jié)點(diǎn)即可。
二叉樹(shù)的三叉鏈表存儲(chǔ)
三叉鏈表存儲(chǔ)的思想是讓每個(gè)節(jié)點(diǎn)不僅“記住”它的左右兩個(gè)子節(jié)點(diǎn),還要“記住”它的父節(jié)點(diǎn),因此需要為每個(gè)節(jié)點(diǎn)增加left,right和parent三個(gè)指針,分別引用該節(jié)點(diǎn)的左,右兩個(gè)子節(jié)點(diǎn)和父節(jié)點(diǎn)。因此,三叉鏈表存儲(chǔ)的每個(gè)節(jié)點(diǎn)有如下圖的結(jié)構(gòu):
three_tree.PNG
因此三叉鏈表存儲(chǔ)的二叉樹(shù)的節(jié)點(diǎn)大致如下:
class Node{
Object data;
Node left;
Node right;
Node parent;
}
對(duì)于這種三叉鏈表存儲(chǔ)的二叉樹(shù),如果程序需要,為指定節(jié)點(diǎn)添加子節(jié)點(diǎn)也非常容易,除了要維護(hù)父節(jié)點(diǎn)的left,right引用之外,還要維護(hù)新增節(jié)點(diǎn)的parent引用。
遍歷二叉樹(shù)
遍歷二叉樹(shù)指的是按某種規(guī)律依次訪問(wèn)二叉樹(shù)的每個(gè)節(jié)點(diǎn),對(duì)二叉樹(shù)的遍歷過(guò)程就是講非線性結(jié)構(gòu)的二叉樹(shù)的節(jié)點(diǎn)排列成線性序列的過(guò)程。
如果采用順序結(jié)構(gòu)來(lái)保存二叉樹(shù),程序遍歷二叉樹(shù)非常容易,無(wú)須進(jìn)行任何思考,直接遍歷底層數(shù)組即可。如果采用鏈表來(lái)保存二叉樹(shù)的節(jié)點(diǎn),則有以下兩種遍歷方式。
深度優(yōu)先遍歷:這種遍歷算法將先訪問(wèn)到樹(shù)中最深層次的節(jié)點(diǎn)
廣度優(yōu)先遍歷:這種遍歷算法將逐層訪問(wèn)每層的節(jié)點(diǎn),先訪問(wèn)根(第一層)節(jié)點(diǎn),然后訪問(wèn)第二層的節(jié)點(diǎn).....一次類推。因此,廣度優(yōu)先遍歷方法又被稱為按層遍歷。
先(前)序遍歷二叉樹(shù)
中序遍歷二叉樹(shù)
后序遍歷二叉樹(shù)
如果L,D,W表示左子樹(shù)、根、右子樹(shù),習(xí)慣上總是必須先遍歷左子樹(shù),后遍歷右子樹(shù),根據(jù)遍歷根節(jié)點(diǎn)的順序不同,上面三種算法可表示如下。
DLR:先序遍歷
LDR:中序遍歷
LRD:后序遍歷
深度遍歷的先序遙歷、中序遍歷、后序遍歷這三種遍歷方式的名稱都是針對(duì)根節(jié)點(diǎn)(D)而言的。先處理根節(jié)點(diǎn)(D)時(shí)就稱為先序遍歷。其次處理根節(jié)點(diǎn)(D)時(shí)就稱為中序遍歷;最后處理根節(jié)點(diǎn)(D)時(shí)就稱為后序遍歷。
先序遍歷
先序遍歷指先處理根節(jié)點(diǎn),其處理順序如下:
(1) 訪問(wèn)根節(jié)點(diǎn)
(2) 遞歸遍歷左子樹(shù)
(3) 遞歸遍歷右子樹(shù)
中序遍歷
中序遍歷指其次處理根節(jié)點(diǎn).其處理順序如下。
(1) 遞歸遍歷左子樹(shù)
(2) 訪問(wèn)根節(jié)點(diǎn)
(3) 遞歸遍歷右子樹(shù)
后序遍歷
后序遍歷指最后處理根節(jié)點(diǎn),其處理順序如下。
(1) 遞歸遍歷左子樹(shù)
(2) 遞歸遍歷右子樹(shù)
(3) 訪問(wèn)根節(jié)點(diǎn)
廣度優(yōu)先(按層)遍歷
廣度優(yōu)先遍歷又稱為按層遍歷,整個(gè)遍歷算法是先遍歷幾叉樹(shù)的第一層(根節(jié)點(diǎn)),再遍歷根節(jié)點(diǎn)的兩個(gè)子’節(jié)點(diǎn)(第二層)……依此類推,逐層遍歷二叉樹(shù)的所有節(jié)點(diǎn)。
為了實(shí)現(xiàn)廣度優(yōu)先遍歷,可以借助于具有FIFO特征的隊(duì)列來(lái)實(shí)現(xiàn)。如下所示。
建一個(gè)隊(duì)列(先進(jìn)先出),把樹(shù)的根節(jié)點(diǎn)壓入隊(duì)列。
從隊(duì)列中彈出一個(gè)節(jié)點(diǎn)(第一個(gè)彈出的就是根節(jié)點(diǎn)),然后把改節(jié)點(diǎn)的左,右節(jié)點(diǎn)壓入隊(duì)列,如果沒(méi)有子節(jié)點(diǎn),則說(shuō)明已經(jīng)達(dá)到葉子節(jié)點(diǎn)了。
用循環(huán)重復(fù)執(zhí)行2步,知道隊(duì)列為空。當(dāng)隊(duì)列為空時(shí),說(shuō)明所有的葉子節(jié)點(diǎn)(深度最深的層)都已經(jīng)經(jīng)過(guò)了隊(duì)列,也就完成了遍歷。
轉(zhuǎn)換方法
由于二叉樹(shù)是一種更“確定”(它的每個(gè)節(jié)點(diǎn)最多只有兩個(gè)子節(jié)點(diǎn))的數(shù)據(jù)結(jié)構(gòu),因此不管是存儲(chǔ)、增加、刪除節(jié)點(diǎn),還是遍歷節(jié)點(diǎn),程序都可以更簡(jiǎn)單、方便地實(shí)現(xiàn)口反之,由于樹(shù)的每個(gè)節(jié)點(diǎn)具有個(gè)數(shù)不確定的節(jié)點(diǎn),因此程序?qū)崿F(xiàn)起來(lái)更復(fù)雜。
為了充分利用二義樹(shù)的簡(jiǎn)單易用性,可以將普通樹(shù)轉(zhuǎn)換為二叉樹(shù),以二叉樹(shù)的形式來(lái)保存柞通樹(shù),當(dāng)程序需要樹(shù)時(shí),再將悅義樹(shù)轉(zhuǎn)換為普通樹(shù)。
森林其實(shí)更簡(jiǎn)單,如果將一棵伶通樹(shù)的根節(jié)點(diǎn)去掉,這棵樹(shù)就變成了森林?;蛘呖梢赞D(zhuǎn)換一下思維,森林其實(shí)就是有多個(gè)根節(jié)點(diǎn)的樹(shù)。
森林,樹(shù)和二叉樹(shù)的轉(zhuǎn)換
有序樹(shù),森林和二叉樹(shù)之間有一一映射的關(guān)系,可以進(jìn)行互相轉(zhuǎn)換。
多叉樹(shù)向二叉樹(shù)的方法如下:
(1)加虛線:同一個(gè)父節(jié)點(diǎn)的相鄰兄弟節(jié)點(diǎn)之間加虛線
(2)抹實(shí)線:每個(gè)節(jié)點(diǎn)只保留它與最左子節(jié)點(diǎn)的連線,與其他字節(jié)點(diǎn)的連線都被抹掉。
(3)虛改實(shí):虛線改為實(shí)線
如圖就是多叉圖向二叉樹(shù)轉(zhuǎn)換的結(jié)果
forest_tree.PNG
圖中的虛線就是新增的“父子”關(guān)系。這個(gè)轉(zhuǎn)換結(jié)果來(lái)看,多叉樹(shù)1轉(zhuǎn)換為二叉樹(shù)的方法的關(guān)鍵思想就是:所有子節(jié)點(diǎn)只保留子節(jié)點(diǎn),其他子節(jié)點(diǎn)轉(zhuǎn)為左子節(jié)點(diǎn)的右子節(jié)點(diǎn)鏈。
按照這個(gè)轉(zhuǎn)換思路,森林也可轉(zhuǎn)換為二叉樹(shù)————只要把森林當(dāng)成一顆根節(jié)點(diǎn)被刪除的多叉樹(shù)即可。下圖示范了將森林轉(zhuǎn)換為二叉樹(shù)的結(jié)果。
forest_to_tree.PNG
反過(guò)來(lái),二叉樹(shù)也可恢復(fù)出對(duì)應(yīng)的多叉樹(shù),森林,恢復(fù)方法如下:
-(1)加虛線:若某節(jié)點(diǎn)I是父節(jié)點(diǎn)的左子節(jié)點(diǎn),則為該節(jié)點(diǎn)I的右孩子鏈的所有節(jié)點(diǎn)分別于節(jié)點(diǎn)I的父節(jié)點(diǎn)添加連線
(2)抹線:把有虛線的節(jié)點(diǎn)于原父節(jié)點(diǎn)的連線抹去
(3)整理:虛改實(shí)并按層排列
把二叉樹(shù)轉(zhuǎn)換為多叉樹(shù)
two_tree_more_tree.PNG
如果二叉樹(shù)的根節(jié)點(diǎn)有右子節(jié)點(diǎn)————右子節(jié)點(diǎn)就代表根節(jié)點(diǎn)的兄弟節(jié)點(diǎn),這種情況會(huì)轉(zhuǎn)換得到森林。
把二叉樹(shù)轉(zhuǎn)換為森林
tree_to_forest.PNG
樹(shù)的鏈表存儲(chǔ)
根據(jù)上面介紹的理論,二義樹(shù)可以和多叉樹(shù)之間進(jìn)行自由轉(zhuǎn)換,因此可以得到普通樹(shù)的另外一種保存方式:以二義樹(shù)的形式保存多叉樹(shù),實(shí)際需要的時(shí)候再將二叉樹(shù)轉(zhuǎn)換為普通樹(shù)。
至于到底以哪種方式來(lái)保存二叉樹(shù),完全是自由的。通常會(huì)選擇使用三叉鏈表存儲(chǔ)方式來(lái)保存二叉樹(shù),這樣得到的二叉樹(shù)操作起來(lái)更方便,進(jìn)行二叉樹(shù)和多叉樹(shù)之間轉(zhuǎn)換時(shí)也更方便。
哈夫曼樹(shù)
哈夫曼樹(shù)又被稱為最優(yōu)二叉樹(shù),是一種帶權(quán)路徑最短的二叉樹(shù)。哈夫曼樹(shù)是二叉樹(shù)的一種應(yīng)用,在信息檢索中很常用.
哈夫曼樹(shù)的定義和基本概念
在介紹哈夫曼樹(shù)之前先來(lái)介紹一些相關(guān)的概念。
節(jié)點(diǎn)之間的路徑長(zhǎng)度:從一個(gè)節(jié)點(diǎn)到另一個(gè)節(jié)點(diǎn)之間的分支數(shù)量稱為兩個(gè)節(jié)點(diǎn)之間的路徑長(zhǎng)度
樹(shù)的路徑長(zhǎng)度:從根節(jié)點(diǎn)到樹(shù)中的每一個(gè)節(jié)點(diǎn)的路徑長(zhǎng)度之和。
對(duì)于下圖所示的而二叉樹(shù),該樹(shù)的路徑長(zhǎng)度為17.即0+1+2+2+3+4+5==17.
hafuman.PNG
節(jié)點(diǎn)的帶權(quán)路徑長(zhǎng)度:從該節(jié)點(diǎn)到根節(jié)點(diǎn)之間的路徑長(zhǎng)度與節(jié)點(diǎn)的權(quán)的乘積
樹(shù)的帶權(quán)路徑長(zhǎng)度:樹(shù)中所有葉子節(jié)點(diǎn)的帶權(quán)路徑長(zhǎng)度之和。帶權(quán)路徑如圖:
daiquan.PNG
對(duì)于哈夫曼樹(shù),有一個(gè)很重要的定理:對(duì)于具有對(duì)n個(gè)葉子節(jié)點(diǎn)的哈夫曼樹(shù),一共需要2乘以n-1個(gè)節(jié)點(diǎn)。因?yàn)閷?duì)于二叉樹(shù)來(lái)說(shuō),有三種類型節(jié)點(diǎn),即度數(shù)為2的節(jié)點(diǎn)、度數(shù)為1的節(jié)點(diǎn)和度數(shù)為0的葉子節(jié)點(diǎn),而哈夫曼樹(shù)的非葉子節(jié)點(diǎn)都是由兩個(gè)節(jié)點(diǎn)合并產(chǎn)生的,所以不會(huì)出現(xiàn)度
數(shù)為1的節(jié)點(diǎn)。而生成的非葉子節(jié)點(diǎn)的個(gè)數(shù)為葉子節(jié)點(diǎn)個(gè)數(shù)-1因此n個(gè)葉子節(jié)點(diǎn)的哈夫曼樹(shù),一共需要Z乘以n-1個(gè)節(jié)點(diǎn)。
創(chuàng)建哈夫曼樹(shù)
創(chuàng)建哈夫曼樹(shù),可以按如下步驟進(jìn)行:
根據(jù)給定的。個(gè)權(quán)值{wl,w2,...,wn}構(gòu)造n棵二叉樹(shù)的集合F={T1,T2,...,Tn} },F集合中每棵二叉樹(shù)都只有一個(gè)根節(jié)點(diǎn)。
選取F集合中兩棵根節(jié)點(diǎn)的權(quán)值最小的樹(shù)作為左、右子樹(shù)以構(gòu)造一棵新的二叉樹(shù),且將新的二叉樹(shù)的根節(jié)點(diǎn)的權(quán)值設(shè)為左、右子樹(shù)上根節(jié)點(diǎn)的權(quán)值之和。
將新的二叉樹(shù)加入到F集合中,并刪除第2步中被選中的兩棵樹(shù)。
重復(fù)第2和3步,直到F集合中只剩下一棵樹(shù),這棵樹(shù)就是哈夫曼樹(shù)。
下圖顯示了創(chuàng)建哈夫曼樹(shù)的過(guò)程。
hafuman_tree.PNG
哈夫曼編碼
根據(jù)哈夫曼樹(shù)可以解決報(bào)文編碼問(wèn)題。假設(shè)需要對(duì)一個(gè)字符串如“a6cdabcaba”進(jìn)行編碼,將它轉(zhuǎn)換為唯一的二進(jìn)制碼,但要求轉(zhuǎn)換出來(lái)的二進(jìn)制碼的長(zhǎng)度最小。
假設(shè)每個(gè)字符在字符串中出現(xiàn)的頻率為W}其編碼長(zhǎng)度為L(zhǎng),編碼字符有n個(gè),則編碼后二進(jìn)制碼的總長(zhǎng)度為W1L1+W2L2+W3L3+...+WnLn,這正好符合哈夫曼樹(shù)的處理原則。因此可采用哈夫曼樹(shù)的原理構(gòu)造二進(jìn)制編碼,并使電文總長(zhǎng)最短。
對(duì)于“abcdabcaba”字符串,總共只有a,b,c,d,這四個(gè)字符,它們出現(xiàn)的次數(shù)是4,3,2,1次__這相當(dāng)于它們的權(quán)值。于是,將a,b,c,d四個(gè)字符以出現(xiàn)的次數(shù)為權(quán)值構(gòu)造哈夫曼樹(shù),得到如下圖結(jié)構(gòu):
hanfuman1.PNG
從哈夫曼樹(shù)根節(jié)點(diǎn)開(kāi)始,對(duì)左子樹(shù)分配代碼“0”,對(duì)右子樹(shù)分配代碼“1”,一直到達(dá)葉子節(jié)點(diǎn)。然后.將從樹(shù)根沿每條路徑到達(dá)葉子節(jié)點(diǎn)的代碼排列起來(lái),便得到了每個(gè)葉子節(jié)點(diǎn)的哈夫曼編碼。下圖顯示了對(duì)a, b, c, d四個(gè)字符編碼得到的哈夫曼編碼。
hanfuma2.PNG
排序二叉樹(shù)
排序二叉樹(shù)是一種特殊結(jié)構(gòu)的二叉樹(shù),通過(guò)它可以非常方便地對(duì)樹(shù)中的所有節(jié)點(diǎn)進(jìn)行排序和檢索
排序二叉樹(shù)要么是一顆空二叉樹(shù),要么是具有下列性質(zhì)的二叉樹(shù)
若它的左子樹(shù)不空,則左子樹(shù)上所有的節(jié)點(diǎn)的值均小于它的根節(jié)點(diǎn)的值
若它的右子樹(shù)不空,則右子樹(shù)上所有的節(jié)點(diǎn)均大于它的根節(jié)點(diǎn)的值
它的左右子樹(shù)分別為排序二叉樹(shù)。
下圖顯示了一棵排序二叉樹(shù).
對(duì)于排序二叉樹(shù),若按中序遍歷就可以得到由小到大的有序序列。中序遍歷得:
{2,3,4,8,9,9,10,13,15,18)
sort_tree.PNG
創(chuàng)建排序二義樹(shù)的步驟,就是不斷地向排序二義樹(shù)添加節(jié)點(diǎn)的過(guò)程,幾體如下。
以根節(jié)點(diǎn)為當(dāng)前節(jié)點(diǎn)開(kāi)始搜索
拿新節(jié)點(diǎn)的值和當(dāng)前節(jié)點(diǎn)開(kāi)始搜索
如果新節(jié)點(diǎn)的值更大,則以當(dāng)前的右子節(jié)點(diǎn)作為新的當(dāng)前節(jié)點(diǎn)的右子節(jié)點(diǎn)作為新的當(dāng)前節(jié)點(diǎn);如果新節(jié)點(diǎn)的值更小,則以當(dāng)前節(jié)點(diǎn)的右子節(jié)點(diǎn)作為新的當(dāng)前節(jié)點(diǎn)。
重復(fù)第2和3兩個(gè)步驟,直到搜索到合適的葉子節(jié)點(diǎn)。
將新節(jié)點(diǎn)添加為第4步找到的葉子節(jié)點(diǎn)的子節(jié)點(diǎn),如果新節(jié)點(diǎn)更大,則添加為右子節(jié)點(diǎn);否則,添加為左子節(jié)點(diǎn)。
當(dāng)程序從排序二叉樹(shù)中刪除一個(gè)節(jié)點(diǎn)之后,為了讓它依然保持為排序哭叉樹(shù),必須對(duì)該排序二叉樹(shù)進(jìn)行維護(hù)。維護(hù)可分為如下幾種情況。
被刪除節(jié)點(diǎn)是葉子節(jié)點(diǎn),只需將它從其父節(jié)點(diǎn)中刪除。
被刪除轉(zhuǎn)點(diǎn)p只有左子樹(shù)或只有右子樹(shù),如果p是它的父節(jié)點(diǎn)的左子節(jié)點(diǎn),則將p的左子樹(shù)或右子樹(shù)添加成p一節(jié)點(diǎn)的父節(jié)點(diǎn)的左子節(jié)點(diǎn)即可;如果p是它的父節(jié)點(diǎn)的右子節(jié)點(diǎn),則將p的左子樹(shù)或右子樹(shù)添加成P節(jié)點(diǎn)的父節(jié)點(diǎn)的右子節(jié)點(diǎn)即可。簡(jiǎn)單來(lái)說(shuō),如果要側(cè)除的節(jié)點(diǎn)只有一個(gè)子節(jié)點(diǎn),即可用它的子節(jié)點(diǎn)來(lái)代替要側(cè)除的節(jié)點(diǎn)。
被刪除的節(jié)點(diǎn)只有左子樹(shù)的情況
delete_only_left_tree.PNG
被刪除節(jié)點(diǎn)只有右子樹(shù)的情況
delete_only_right_tree.PNG
若被刪除節(jié)點(diǎn)p的左、右子樹(shù)均非空,則有以下兩種做法。
將pL設(shè)為P的父節(jié)點(diǎn)q的左或右子節(jié)點(diǎn)(取決于P是其節(jié)父點(diǎn)q的左、右子節(jié)點(diǎn)),
將pR設(shè)為P節(jié)點(diǎn)的中序前趨節(jié)點(diǎn)s的右子節(jié)點(diǎn)(s是pL最右下的節(jié)點(diǎn),也就是pL子樹(shù)中最大的節(jié)點(diǎn))。采用這種方式刪除節(jié)點(diǎn)的示意圖如下:
delete_left_right.PNG
以P節(jié)點(diǎn)的中序前趨或后繼替代P所指節(jié)點(diǎn),然后從原排序二叉樹(shù)中刪除中序前趨或后繼節(jié)點(diǎn)。簡(jiǎn)單來(lái)說(shuō),就是用大于p的最小節(jié)點(diǎn)或小于P的最大節(jié)點(diǎn)代替P節(jié)點(diǎn)點(diǎn),采
用這種方式刪除節(jié)點(diǎn)的示意圖如下圖:
delete_left_right_center.PNG
紅黑樹(shù)
排序二叉樹(shù)雖然可以快速檢索,但在最壞的情況下,如果插入的節(jié)點(diǎn)集本身就是有序的,要么是由小到大排列,要么是由大到小排列,那么最后得到的排序二義樹(shù)將變成鏈表:所有節(jié)點(diǎn)只有左節(jié)點(diǎn)(如果插入節(jié)點(diǎn)集合本身是由大到小排列的),或者所有節(jié)點(diǎn)只有右節(jié)點(diǎn)(如果
插入節(jié)點(diǎn)集合本身是由小到大排列的)。在這種情況下,排序二叉樹(shù)就變成了普通鏈表,其檢索效率就會(huì)很低。
為了改變排序二叉樹(shù)存在的不足,對(duì)二叉樹(shù)進(jìn)行改進(jìn)————紅黑樹(shù),他將這種排序二叉樹(shù)稱為“對(duì)稱二叉B樹(shù)”。
紅黑樹(shù)是一個(gè)更高效的檢索二叉樹(shù),因此常常用來(lái)實(shí)現(xiàn)關(guān)聯(lián)數(shù)組。典型的,JDK提供的集合類TreeMap本身就是一顆紅黑樹(shù)的實(shí)現(xiàn)。
紅黑樹(shù)在原有的排序二叉樹(shù)上增加如下幾個(gè)要求:
性質(zhì)l:每個(gè)節(jié)點(diǎn)要么是紅色,要么是黑色。
性質(zhì)2:根節(jié)點(diǎn)永遠(yuǎn)是黑色的。
除質(zhì)3:所有的葉子節(jié)點(diǎn)都是空節(jié)點(diǎn)(即null),并且是黑色的。
性質(zhì)4:每個(gè)紅色節(jié)點(diǎn)的兩個(gè)子節(jié)點(diǎn)都是黑色的。(從每個(gè)葉子到根的路徑上不會(huì)有兩個(gè)連續(xù)的紅色節(jié)點(diǎn)。)
性質(zhì)5:從任一節(jié)點(diǎn)到其子樹(shù)中每個(gè)葉子節(jié)點(diǎn)的路徑都包含相同數(shù)量的黑色節(jié)點(diǎn)。
java實(shí)現(xiàn)的紅黑樹(shù)結(jié)構(gòu)如下圖:
red_black_tree.PNG
根據(jù)性質(zhì)5,紅黑樹(shù)從根節(jié)點(diǎn)到每個(gè)葉子節(jié)點(diǎn)的路徑都包含相同數(shù)量的黑色節(jié)點(diǎn),因此從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的路徑中包含的黑色節(jié)點(diǎn)數(shù)被稱為樹(shù)的“黑色高度(black-height)".
性質(zhì)4則保證了從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的最長(zhǎng)路徑的一長(zhǎng)度不會(huì)超過(guò)任何其他路徑的2倍。假如有一棵黑色高度為3的紅黑樹(shù),從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的最短路徑長(zhǎng)度是2,該路徑上全是黑色節(jié)點(diǎn)〔黑色節(jié)點(diǎn)-黑色節(jié)點(diǎn)-黑色節(jié)點(diǎn))。最長(zhǎng)路徑也只可能為4,在每個(gè)黑色節(jié)點(diǎn)之間插入一個(gè)紅色節(jié)點(diǎn)〔黑色節(jié)點(diǎn)-紅色節(jié)點(diǎn)-黑色書(shū)點(diǎn)-紅色節(jié)點(diǎn)-黑色節(jié)點(diǎn)),性質(zhì)4保證絕不可能插入更多的紅色節(jié)點(diǎn)。由此可見(jiàn),紅黑樹(shù)中最長(zhǎng)的路徑就是一條紅黑交替的路徑。
由此可以得出結(jié)論:對(duì)于給定的黑色高度為N的紅黑樹(shù),從根到葉子節(jié)點(diǎn)的最短路徑長(zhǎng)度為N-1,最長(zhǎng)路徑長(zhǎng)度為2*(N-1).
紅黑樹(shù)通過(guò)上面這種限制來(lái)保證它大致是平衡的—因?yàn)榧t黑樹(shù)的高度不會(huì)無(wú)限增高,這樣能保證紅黑樹(shù)在最壞的情況下都是高效的,不會(huì)出現(xiàn)普通排序二叉樹(shù)的情況。
由于紅黑樹(shù)只是一棵特殊的排序二叉樹(shù),因此對(duì)紅黑樹(shù)上的只讀操作與普通排序二叉樹(shù)上的只讀操作完全相同,只是紅黑樹(shù)保持了大致平衡,因此檢索性能更好.
但在紅黑樹(shù)上進(jìn)行插入操作和刪除操作會(huì)導(dǎo)致樹(shù)不再符合紅黑樹(shù)的特征,因此插入操作和刪除操作都需要進(jìn)行一定的維護(hù),以保證插入節(jié)點(diǎn)、刪除節(jié)點(diǎn)后的樹(shù)依然是紅黑樹(shù)。
插入操作
插入操作按如下步驟進(jìn)行:
以排序二叉樹(shù)的方法插入新節(jié)點(diǎn),并將它設(shè)為紅色。
進(jìn)行顏色調(diào)換和樹(shù)旋轉(zhuǎn)
這種顏色調(diào)換和樹(shù)旋轉(zhuǎn)就比較復(fù)雜了,下面將分情況進(jìn)行介紹。在介紹中,把新插入的節(jié)點(diǎn)定義為N節(jié)點(diǎn),把N節(jié)點(diǎn)的父節(jié)點(diǎn)定義為P節(jié)點(diǎn),把P節(jié)點(diǎn)的兄弟節(jié)點(diǎn)定義為U節(jié)點(diǎn),把P節(jié)點(diǎn)的父節(jié)點(diǎn)定義為G節(jié)點(diǎn)。
情形1:新節(jié)點(diǎn)N是樹(shù)的根節(jié)點(diǎn),沒(méi)有父節(jié)點(diǎn)。
在這種情形下,直接將它設(shè)置為黑色以滿足性質(zhì)2。
情形2:新節(jié)點(diǎn)的父節(jié)點(diǎn)P是黑色的
在這種情形下,新插入的節(jié)點(diǎn)是紅色的,因此依然滿足性質(zhì)4。而且因?yàn)樾鹿?jié)點(diǎn)N有兩個(gè)黑色葉子節(jié)點(diǎn),但是由于新節(jié)點(diǎn)N是紅色的,通過(guò)它的每個(gè)子節(jié)點(diǎn)的路徑依然保持相同的黑色節(jié)點(diǎn)數(shù),因此依然滿足性質(zhì)5
3.情形3:父節(jié)點(diǎn)P和父節(jié)點(diǎn)的兄弟節(jié)點(diǎn)U都是紅色的
在這種情形下,程序應(yīng)該將P節(jié)點(diǎn)、U節(jié)點(diǎn)都設(shè)置為黑色,并將P節(jié)點(diǎn)的父節(jié)點(diǎn)設(shè)置為紅色(用來(lái)保持性質(zhì)5)?,F(xiàn)在,新節(jié)點(diǎn)N有了一個(gè)黑色的父節(jié)點(diǎn)P。由于從P節(jié)點(diǎn)、U節(jié)點(diǎn)到根節(jié)點(diǎn)的任何路徑都必須通過(guò)G節(jié)點(diǎn),這些路徑上的黑色節(jié)點(diǎn)數(shù)目沒(méi)有改變(原來(lái)有葉子和G節(jié)點(diǎn)兩個(gè)黑色節(jié)點(diǎn),現(xiàn)在有葉子和P節(jié)點(diǎn)兩個(gè)黑色節(jié)點(diǎn))。
經(jīng)過(guò)上面處理后,紅色的G節(jié)點(diǎn)的父節(jié)點(diǎn)也有可能是紅色的,這就違反了性質(zhì)4,因此還需要對(duì)G節(jié)點(diǎn)遞歸地進(jìn)行整個(gè)過(guò)程〔把G節(jié)點(diǎn)當(dāng)成新插入的節(jié)點(diǎn)進(jìn)行處理)。
下圖顯示了處理過(guò)程:
red_black_tree_1.PNG
情形4:父節(jié)點(diǎn)P是紅色的,而其兄弟節(jié)點(diǎn)U是黑色的或缺少;且新節(jié)點(diǎn)N是父節(jié)點(diǎn)P的右子節(jié)點(diǎn),而父節(jié)點(diǎn)P又是其父節(jié)點(diǎn)G的左子節(jié)點(diǎn)。
在這種情形下,對(duì)新節(jié)點(diǎn)和其父節(jié)點(diǎn)進(jìn)行一次左旋轉(zhuǎn)。接著,按情形5處理以前的父節(jié)點(diǎn)P(也就是把P當(dāng)成新插入的節(jié)點(diǎn))。這將導(dǎo)致某些路徑通過(guò)它們以前不通過(guò)的新節(jié)點(diǎn)N或父節(jié)點(diǎn)P其中之一,但是這兩個(gè)節(jié)點(diǎn)都是紅色的,因此不會(huì)影響性質(zhì)5。
red_black_tree_2.PNG
情形5:父節(jié)點(diǎn)F是紅色的,而其兄弟節(jié)點(diǎn)U是黑色的或缺少:且新節(jié)點(diǎn)N是其父節(jié)點(diǎn)的左子節(jié)點(diǎn),而父節(jié)點(diǎn)F父是其父節(jié)點(diǎn)G的左子節(jié)點(diǎn)。
在這種情形下,需要對(duì)節(jié)點(diǎn)G進(jìn)行一次右旋轉(zhuǎn)口在旋轉(zhuǎn)產(chǎn)生的樹(shù)中,以前的父節(jié)點(diǎn)P現(xiàn)在是新節(jié)點(diǎn)N和節(jié)點(diǎn)G的父節(jié)點(diǎn)。由于以前的節(jié)點(diǎn)G是黑色的(否則父節(jié)點(diǎn)P就不可能是紅色的),切換以前的父節(jié)點(diǎn)P和節(jié)點(diǎn)G的顏色,使之滿足性質(zhì)4。性質(zhì)5也仍然保持滿足,因?yàn)橥ㄟ^(guò)這三個(gè)節(jié)點(diǎn)中任何一個(gè)的所有路徑以前都通過(guò)節(jié)點(diǎn)G,現(xiàn)在它們都通過(guò)以前的父節(jié)點(diǎn)P。在各自的情形下,這都是三個(gè)節(jié)點(diǎn)中唯一的黑色節(jié)點(diǎn)。
red_black_tree_3.PNG
刪除操作
紅黑樹(shù)的刪除操作比插入操作要稍微復(fù)雜一些,實(shí)際上也可按如下步驟進(jìn)行:
以排序二叉樹(shù)的方法刪除指定節(jié)點(diǎn)。
進(jìn)行顏色調(diào)換和樹(shù)旋轉(zhuǎn),使之滿足紅黑樹(shù)特征。
總結(jié)
以上是生活随笔為你收集整理的java 二叉树特点_疯狂java笔记之树和二叉树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: r语言安装ipsolve_R语言矩阵操作
- 下一篇: 京东自动下单软件_黄牛软件自动下单秒杀商