數(shù)據(jù)結(jié)構(gòu)與算法 10: 樹形結(jié)構(gòu)

目錄

一、
二、二叉樹
三、樹、森林與二叉樹的轉(zhuǎn)換

一、樹

樹形結(jié)構(gòu) 是數(shù)據(jù)元素(結(jié)點(diǎn))之間有分支,并且具有層次關(guān)系的結(jié)構(gòu),可用于表示數(shù)據(jù)元素之間存在的一對(duì)多關(guān)系。
樹(Tree) 是由n(n≥0)個(gè)結(jié)點(diǎn)構(gòu)成的有限集合,當(dāng)n=0時(shí)稱為空樹。若樹非空,則具有以下兩個(gè)性質(zhì):
(1)有且僅有一個(gè)特定的結(jié)點(diǎn),稱為根(Root)。
(2)其余的結(jié)點(diǎn)可分為m個(gè)互不相交的集合T1,T2,…,Tm,其中每一個(gè)集合都是一棵樹,并且稱為根的子樹( Subtree)。
如下圖所示是有13個(gè)結(jié)點(diǎn)的樹,A是根,其余結(jié)點(diǎn)分成三個(gè)互斥的集合T1={B,E,F(xiàn),K,L}、T2={C,G}、T3={D,H,I,J,M},T1、T2、T3都是A的子樹,其本身也是一棵樹。

image
樹的基本術(shù)語:
**樹結(jié)點(diǎn)( Tree Node)** :樹中一個(gè)獨(dú)立單元。包含一個(gè)數(shù)據(jù)元素及若干指向其子樹的分支,如上圖中的A、B、C、D等。
**樹根(Root)** :樹中唯一沒有前驅(qū)的結(jié)點(diǎn),如上圖中的A結(jié)點(diǎn)。
**結(jié)點(diǎn)的度( Node Degree)** :結(jié)點(diǎn)擁有的子樹數(shù),稱為結(jié)點(diǎn)的度。例如,在上圖中A的度為3,B的度為2,K的度為0。
**樹的度( Tree Degree)** :樹中各結(jié)點(diǎn)的度的最大值。如上圖中樹的度為3。
**樹葉(Leaf)** :度為0的結(jié)點(diǎn)。例如,在圖中,K、L、F、G、1、J、M都是樹葉,也稱葉結(jié)點(diǎn)。除根和葉子以外的其他結(jié)點(diǎn)稱為中間結(jié)點(diǎn)。
**雙親( Parent)和孩子( Child)** :把一個(gè)樹結(jié)點(diǎn)的直接前驅(qū)稱為該結(jié)點(diǎn)的雙親;反之;把一個(gè)樹結(jié)點(diǎn)的所有直接后繼稱為該結(jié)點(diǎn)的孩子。例如,上圖中,結(jié)點(diǎn)B是結(jié)點(diǎn)A的孩子,結(jié)點(diǎn)A是結(jié)點(diǎn)B的雙親。
**兄弟( Sibling)** :同一雙親的孩子之間互稱為兄弟。例如,上圖中,結(jié)點(diǎn)K、L互為兄弟,結(jié)點(diǎn)H、I、J互為兄弟。將這些關(guān)系進(jìn)一步推廣,結(jié)點(diǎn)的祖先就是從根到該結(jié)點(diǎn)的所經(jīng)分支上的所有結(jié)點(diǎn)。以某結(jié)點(diǎn)為根的子樹中的任一結(jié)點(diǎn)都稱為該結(jié)點(diǎn)的子孫。此外雙親在同一層上的結(jié)點(diǎn)互為堂兄弟.
**樹的層次( Level)和深度( Depth)** :從根算起,根為第一層,根的孩子為第二層,樹中任一結(jié)點(diǎn)的層次等于它的雙親的層次加1。樹中各結(jié)點(diǎn)層次的最大值稱為樹的深度或高度。例如,上圖中的樹的深度為4。
**有序樹和無序樹( Ordered Tree8。 Unordered Tree)** :如果樹中結(jié)點(diǎn)的各子樹可看成從左至右是有次序的(即不能互換),則稱該樹為有序樹,否則稱為無序樹。在有序樹最左邊子樹的根稱為第一孩子,最右邊子樹的根稱為最后一個(gè)孩子。
**森林( Forest)** :m(m≥0)棵互不相交的樹的集合。對(duì)樹中每個(gè)結(jié)點(diǎn)而言,其子樹的集合即為森林。由此也可以以森林和樹的相互遞歸定義來描述樹。

1.1、樹的存儲(chǔ)結(jié)構(gòu)

樹是一種非線性結(jié)構(gòu)。為了存儲(chǔ)一探樹,必須把樹中各結(jié)點(diǎn)之間一對(duì)多的關(guān)系反映在存儲(chǔ)結(jié)構(gòu)中。由于在一個(gè)m階的普通樹中,每一個(gè)結(jié)點(diǎn)的孩子可是0~m個(gè),所以相對(duì)于二又樹而言,樹的存錯(cuò)結(jié)構(gòu)要復(fù)雜,一般有如下幾種存儲(chǔ)結(jié)構(gòu):

  • 1.1.1、雙親表示法

雙親表示法是以一組連續(xù)空間存儲(chǔ)樹的結(jié)點(diǎn),同時(shí)在每個(gè)結(jié)點(diǎn)中附設(shè)一個(gè)標(biāo)志指示其雙親結(jié)點(diǎn)在表中的位置,該存儲(chǔ)結(jié)構(gòu)定義如下;

image
  • 1.1.2、孩子表示法

由于樹中的每個(gè)結(jié)點(diǎn)可能有多棵子樹,因此可以采用多重鏈表來表示,即每個(gè)結(jié)點(diǎn)有多個(gè)指針域,分別指向其孩子結(jié)點(diǎn)。
如圖6-13所示,樹的孩子表示法需要按照樹的度m為每個(gè)結(jié)點(diǎn)分配指針域,而每個(gè)結(jié)點(diǎn)的孩子個(gè)數(shù)可不同,當(dāng)m很大時(shí),指針域的存儲(chǔ)單元利用率很低。如果按每個(gè)結(jié)點(diǎn)的實(shí)際孩子數(shù)來分配指針單元,結(jié)點(diǎn)的大小可變,會(huì)給存儲(chǔ)管理帶來不便。一個(gè)較好的解決辦法就是為每個(gè)結(jié)點(diǎn)建立一個(gè)孩子鏈表,n個(gè)結(jié)點(diǎn)的樹由n個(gè)這樣的單鏈表組成,每個(gè)鏈表的表頭結(jié)點(diǎn)存放該結(jié)點(diǎn)的值和指向其孩子的頭指針,如圖614所示

image
  • 1.1.3、孩子兄弟表示法

孩子兄弟表示法又稱樹的二又鏈表表示法。樹中的每個(gè)結(jié)點(diǎn)由三個(gè)域組成:data域 結(jié)點(diǎn)的數(shù)據(jù)信息, firstchild域?yàn)橹赶蚪Y(jié)點(diǎn)的第一個(gè)孩子的指針, nextbrother域?yàn)橹赶蛳乱粋€(gè)兄弟的指針,如下圖所示。
由下圖可以看出,每個(gè)結(jié)點(diǎn)的左指針指向孩子結(jié)點(diǎn),而右指針指向兄弟結(jié)點(diǎn),并且根結(jié)點(diǎn)的右指針為空。樹的孩子兄弟表示法為實(shí)現(xiàn)樹、森林與二又樹之間的轉(zhuǎn)換提供了基礎(chǔ)。

image

二、二叉樹

二叉樹 就是度為2的有序樹,是最重要的一種樹形結(jié)構(gòu)。二又樹的存儲(chǔ)和處理比普通樹簡(jiǎn)單,同時(shí)普通樹都可以方便地轉(zhuǎn)化為二又樹來存儲(chǔ)和處理。
二叉樹( Binary Tree) 是一種特殊的樹形結(jié)構(gòu)。定義如下:
(1)由n(n≥0)個(gè)結(jié)點(diǎn)所構(gòu)成的集合,此集合可以為空。
(2)二叉樹的根結(jié)點(diǎn)下可分為兩個(gè)互不相交的子樹,子樹有左右之分,次序不能任意顛倒,稱為左子樹和右子樹:且左右子樹均為二叉樹。

image

2.1、二叉樹的性質(zhì)

二叉樹是有序樹的特例,具有下列重要性質(zhì):
性質(zhì)1、在二叉樹的第i層上至多有2^(i-1)個(gè)結(jié)點(diǎn)(i>=1)。
性質(zhì)2、深度為k的二叉樹至多有2^(k) - 1個(gè)結(jié)點(diǎn),(k>=1)。
性質(zhì)3、對(duì)任何一顆二叉樹T,如果其終端結(jié)點(diǎn)數(shù)為n0,度為2的結(jié)點(diǎn)數(shù)為n2,則n0 = n2 + 1;
性質(zhì)4、具有n個(gè)結(jié)點(diǎn)的完全二叉樹的深度為 (logn以2為底的對(duì)數(shù) + 1) 。
性質(zhì)5、如果對(duì)一棵有n結(jié)點(diǎn)的深度為(logn以2為底的對(duì)數(shù) + 1) ,完全二叉樹的結(jié)點(diǎn)按層序編號(hào),同層按從左至右,則對(duì)任一結(jié)點(diǎn)i(1 ≤ i ≤ n)。于是有:
(1)如果=1,則結(jié)點(diǎn)i是二叉樹的根,無雙親;如果i>1,則其雙親 PARENT(i)是結(jié)點(diǎn)i/2。
(2)如果2i>n,則結(jié)點(diǎn)i無左孩子(結(jié)點(diǎn)i為葉子結(jié)點(diǎn));否則,其左孩子 LCHILD(i)是結(jié)點(diǎn)2i。
(3)如果2i+1>n,則結(jié)點(diǎn)i無右孩子;否則,其右孩子 RCHILD(i)是結(jié)點(diǎn)2i+1。

image

一棵深度為k且有2^k - 1個(gè)結(jié)點(diǎn)的二叉樹稱為 滿二叉樹 。滿二叉樹的特點(diǎn)是每一層上的結(jié)點(diǎn)數(shù)都是最大結(jié)點(diǎn)數(shù)。
對(duì)滿二叉樹的結(jié)點(diǎn)進(jìn)行連續(xù)編號(hào),約定編號(hào)從根結(jié)點(diǎn)起,自上而下,自左至右。由此可引出完全二叉樹的定義。深度為k、有n個(gè)結(jié)點(diǎn)的二叉樹,當(dāng)且僅當(dāng)其每一個(gè)結(jié)點(diǎn)都與深度為k的滿二叉樹中編號(hào)從1~n的結(jié)點(diǎn)一一對(duì)應(yīng)時(shí),稱為 完全二叉樹 。如上圖所示完全二叉樹具有的特點(diǎn)是:
(1)葉子結(jié)點(diǎn)只可能在層次最大的兩層上出現(xiàn)。
(2)對(duì)任一結(jié)點(diǎn),若其右分支下的子孫的最大層次為r,則其左分支下的子孫的最大層次必為r或r+1。

2.2、二叉樹的存儲(chǔ)結(jié)構(gòu)

  • 2.2.1、順序存儲(chǔ)結(jié)構(gòu)

用一組地址連續(xù)的存儲(chǔ)單元存儲(chǔ)二叉樹中的各個(gè)結(jié)點(diǎn)。為了便于對(duì)二叉樹結(jié)點(diǎn)進(jìn)行查找或處理,存儲(chǔ)時(shí)需要將普通二叉樹的各個(gè)結(jié)點(diǎn)按照它們?cè)谕耆鏄涞膶?duì)應(yīng)結(jié)點(diǎn)位置依次存放到數(shù)組相應(yīng)的存儲(chǔ)單元中。如圖所示,二又樹的順序存儲(chǔ)結(jié)構(gòu)定義如下:

image

一般來說,順序存儲(chǔ)結(jié)構(gòu)只適用于完全二叉樹或滿二叉樹的存儲(chǔ),因?yàn)槠胀ǘ鏄洳捎庙樞虼鎯?chǔ)結(jié)構(gòu)進(jìn)行存儲(chǔ)時(shí),將導(dǎo)致存儲(chǔ)單元的浪費(fèi)。最壞情況下,對(duì)于一個(gè)深度為k且只有k個(gè)結(jié)點(diǎn)的右支樹來說,存儲(chǔ)時(shí)需要2^k-1個(gè)存儲(chǔ)單元。

  • 2.2.2、鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)

采用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)存儲(chǔ)二叉樹時(shí),可以根據(jù)樹中的結(jié)點(diǎn)數(shù)動(dòng)態(tài)申請(qǐng)所需要的結(jié)點(diǎn),從而避免存儲(chǔ)空間的浪費(fèi)。
由二叉樹的定義可知,每個(gè)二叉樹的結(jié)點(diǎn)由一個(gè)數(shù)據(jù)元素和分別指向其左、右子樹的兩個(gè)分支組成。因此,定義二叉樹的結(jié)點(diǎn)結(jié)構(gòu)時(shí)至少應(yīng)包含三個(gè)域:數(shù)據(jù)域和左、右指針域。其中,數(shù)據(jù)域保存結(jié)點(diǎn)的信息左指針域存放指向其左子樹根的信息右指針域存放指向其右子樹根的信息,如下圖所示。有時(shí),為了便于找到結(jié)點(diǎn)的雙親,則可在上述結(jié)點(diǎn)結(jié)構(gòu)中增加一個(gè)指向其雙親結(jié)點(diǎn)的指針域,如下圖所示。利用這兩種結(jié)點(diǎn)結(jié)構(gòu)所得的二叉樹的存儲(chǔ)結(jié)構(gòu)分別稱為二又鏈表和三又鏈表。如下圖所示二叉樹的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)。

image
image

2.3、遍歷二叉樹

二叉樹的遍歷 是指按照一定次序訪問樹中所有結(jié)點(diǎn),并且每個(gè)結(jié)點(diǎn)僅被訪問一次的過程。它是二叉樹最基本的運(yùn)算,也是二叉樹中所有其他運(yùn)算的基礎(chǔ)。遍歷二叉樹的實(shí)質(zhì)是對(duì)二叉樹的線性化過程,即遍歷的結(jié)果是將非線性結(jié)構(gòu)的樹中結(jié)點(diǎn)排成一個(gè)線性序列,二叉樹的遍歷按訪問根結(jié)點(diǎn)的先后次序不同,可分為 先序遍歷、中序遍歷 和 后序遍歷
下面對(duì)二叉樹的遍歷討論中,二叉樹都采用二叉鏈表的存儲(chǔ)結(jié)構(gòu)。

  • 1、二叉樹的先序遍歷

根據(jù)二叉樹的遞歸特性,先序遍歷二叉樹的遞歸
過程如下:
(1)訪問根結(jié)點(diǎn)。
(2)先序遍歷左子樹
(3)先序遍歷右子樹。

  • 2、二叉樹的中序遍歷

中序遍歷二叉樹的遞歸過程如下:
(1)中序遍歷左子樹。
(2)訪問根結(jié)點(diǎn)。
(3)中序遍歷右子樹。

  • 3、二叉樹的后序遍歷

后序遍歷二叉樹的遞歸過程如下:
(1)后序遍歷左子樹。
(2)后序遍歷右子樹。
(3)訪問根結(jié)點(diǎn)。

image

遍歷二又樹的算法中的基本操作是訪問結(jié)點(diǎn),則無論按哪種次序進(jìn)行遍歷,對(duì)含有n個(gè)結(jié)點(diǎn)的二又樹,其時(shí)間復(fù)雜度均為0(n)。所需輔助空間為遍歷過程中棧的最大容量,即樹的深度,最壞情況下為n,則空間復(fù)雜度也為O(n)。

三、樹、森林與二叉樹的轉(zhuǎn)換

二叉樹的二叉鏈表表示法和樹的孩子兄弟表示法都是以二叉鏈表作為存儲(chǔ)結(jié)構(gòu),結(jié)點(diǎn)的定義相同,只是解釋不同。因此,可以找到樹和二又樹之間的對(duì)應(yīng)關(guān)系,即給定一棵樹,可以找到唯一的一棵二叉樹與之對(duì)應(yīng)。

image

森林是樹的有限集合,可以將森林看成一棵樹,其中所有樹的根結(jié)點(diǎn)彼此看成兄弟結(jié)點(diǎn)。這樣也可以導(dǎo)出森林和二叉樹的對(duì)應(yīng)關(guān)系。

image

下面給出森林和二叉樹相互轉(zhuǎn)換的遞歸定義:
1、森林轉(zhuǎn)換成二叉樹
若F={T1,T2,…,Tm}是森林(m≥0),則可按如下規(guī)則轉(zhuǎn)換成一棵二叉樹B=(root,LB,RB)。
(1)若m=0,則B為空樹。
(2)若m>0,則B的根root即為森林F中第一棵樹的根ROOT(T1);B的左子樹LB是從森林的第一棵樹T1中根結(jié)點(diǎn)的子樹森林F1={T1,T2,…,Tm}轉(zhuǎn)換而成的二叉樹;B的右子樹RB是從森林F中除T1外的剩余部分F={T2,T3,…,Tm}轉(zhuǎn)換而成的二叉樹。
具體操作步驟如下:
(1)先將森林中的每一棵樹轉(zhuǎn)換為二叉樹。
(2)按森林中樹的次序,依次將后一棵樹作為前一棵樹的右子樹,并將第一棵樹的根作為目標(biāo)二又樹的根。
2、二叉樹轉(zhuǎn)換成森林
如果B=(roo,LB,RB)是一棵二叉樹,則可按如下規(guī)則轉(zhuǎn)換成森林F={T,,…,Tm}。
(1)若B為空,則F為空。
(2)若B非空,則F中第一棵樹T1的根ROOT(T1)即為二叉樹B的根root;T1中根結(jié)點(diǎn)的子樹森林F1是由B的左子樹LB轉(zhuǎn)換而成的森林;F中除T1之外其余樹組成的森林F'={T2,T3,…,Tm}是由B的右子樹RB轉(zhuǎn)換而成的森林。
具體操作步驟如下:
(1)若二叉樹非空,則二叉樹根及其左子樹為第一棵樹的二叉樹形式。
(2)二又樹根的右子樹又可看作是剩余二叉樹構(gòu)成的森林,再繼續(xù)分離出一棵樹,直至產(chǎn)生一顆沒有右子樹的二叉樹為止。

注:文中的圖片均轉(zhuǎn)摘自網(wǎng)絡(luò)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,616評(píng)論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,112評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,355評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,727評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,928評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,165評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評(píng)論 1 282
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,585評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,892評(píng)論 2 372

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