版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第6章樹(shù)
?2二叉樹(shù)
6.3遍歷二叉樹(shù)
第六章樹(shù)
第6章樹(shù)
樹(shù)形結(jié)構(gòu)是一種應(yīng)用十分廣泛和重要的非線性數(shù)據(jù)結(jié)
構(gòu),是一種以分支關(guān)系定義的層次結(jié)構(gòu)。在這種結(jié)構(gòu)中,
每個(gè)數(shù)據(jù)元素至多只有一個(gè)前趨,但可以有多個(gè)后繼;數(shù)
據(jù)元素之間的關(guān)系是一對(duì)多的層次關(guān)系。樹(shù)形結(jié)構(gòu)主要用
于描述客觀世界中具有層次結(jié)構(gòu)的數(shù)據(jù)關(guān)系。
本章重點(diǎn)討論樹(shù)與二叉樹(shù)的概念、性質(zhì)、存貯結(jié)構(gòu)及
其各種運(yùn)算,并研究一般樹(shù)、森林和二叉樹(shù)的轉(zhuǎn)換關(guān)系;
此外,作為樹(shù)形結(jié)構(gòu)的應(yīng)用,介紹了哈夫曼樹(shù)及其哈夫曼
編碼。
第六章樹(shù)
ti6.1樹(shù)的基本概念
6.1.1樹(shù)的定義及表示
1、樹(shù)形結(jié)構(gòu)示例
張紅軍
(a)一個(gè)家族結(jié)構(gòu)示意圖
第六章樹(shù)
校長(zhǎng)辦公室
計(jì)算機(jī)學(xué)院科研處人事處財(cái)務(wù)處教務(wù)處
計(jì)算機(jī)系電信系數(shù)學(xué)系人事科勞資科教務(wù)科教材科
(b)行政結(jié)構(gòu)樹(shù)形示意圖
6.1樹(shù)形結(jié)構(gòu)示意圖
第六章樹(shù)—
--------------__
■2、樹(shù)的定義
樹(shù)(Tree)是n(n>0)個(gè)結(jié)點(diǎn)的有限集合T,當(dāng)n=0時(shí)不焉用樹(shù),
否則,稱為非空樹(shù)。在任一棵非空樹(shù)中:
(1)有且僅有一個(gè)稱為樹(shù)根的結(jié)點(diǎn)。
(2)除根結(jié)點(diǎn)之外的其余結(jié)點(diǎn)可分為m(m>0)個(gè)互不相交的集
合TLT2,…,Tm,其中每一個(gè)集合本身又都是一棵樹(shù),一般稱為
根的子樹(shù)。
樹(shù)的定義是一個(gè)遞歸的定義,它反映了樹(shù)的固有特性,即一棵樹(shù)
由若干棵子樹(shù)構(gòu)成,且各子樹(shù)間互不相交,而每棵子樹(shù)又由若干棵更
小的子樹(shù)構(gòu)成。例如,在圖6.2中,(a)是只有一個(gè)根結(jié)點(diǎn)的樹(shù);(b)
是有8個(gè)結(jié)點(diǎn)的一般樹(shù),其中A是根,其余結(jié)點(diǎn)分成三個(gè)互不相交的子
集:T1={B、E、F},T2={C},T3={D、G、H},而且它們都是A的子
樹(shù),且其本身也是一棵樹(shù)。
第六章樹(shù)
(a)只有根結(jié)點(diǎn)的樹(shù)(b)一般樹(shù)
6.2樹(shù)示例
樹(shù)的表示方法有樹(shù)形表示、集合表示、凹入表示和廣義表等4種。圖
6.3給出了樹(shù)的其它表示形式,如(a)為集合表示法或范氏圖法,(b)
為凹入表示法或縮格法,(c)為廣義表表示法或嵌套括弧法等。
ni/〃/〃/〃〃/〃〃〃〃〃/“/,
D[〃〃/〃〃〃〃〃〃//
D|〃〃〃/〉必〃〃〃〃
E〃〃〃〃〃〃
I7177777777777
p[7777777777777777777(A(B(E,F),C,D(G,H)))
D1〃〃〃〃〃〃〃〃〃/
IcI卜I〃〃〃〃〃/
H
11!\?/〃//〃//〃//〃//〃if/
(a)集合表示(b)凹入表示(c)廣義表表示
圖6.3樹(shù)的其它表示法
第六章樹(shù)
|6.L2樹(shù)的常用術(shù)語(yǔ)K*
樹(shù)的結(jié)點(diǎn):是指一個(gè)數(shù)據(jù)元素及若干指向其子樹(shù)的分支,通常用一
個(gè)結(jié)構(gòu)體或記錄來(lái)描述,在樹(shù)形表示中用一個(gè)圓圈及短線表示。
結(jié)點(diǎn)的度:是指結(jié)點(diǎn)的子樹(shù)數(shù)目。
葉子或終端結(jié)點(diǎn):是指度為零的結(jié)點(diǎn)。
分支結(jié)點(diǎn)或非終端結(jié)點(diǎn):是指度不為零的結(jié)點(diǎn)。
樹(shù)的度:是指樹(shù)中各結(jié)點(diǎn)度的最大值。
有時(shí),在實(shí)際應(yīng)用中也引用家族樹(shù)中的一些習(xí)慣用語(yǔ)來(lái)描述樹(shù),如
孩子、雙親、祖先、子孫和兄弟等。如將某結(jié)點(diǎn)的子樹(shù)的根稱為該結(jié)點(diǎn)
的孩子,相應(yīng)地,將該結(jié)點(diǎn)稱為孩子的雙親;同一個(gè)雙親的孩子之間互
稱為兄弟等等。祖先則是從根結(jié)點(diǎn)到該結(jié)點(diǎn)所經(jīng)過(guò)分支上的所有結(jié)點(diǎn),
而以某結(jié)點(diǎn)作為根的子樹(shù)中任一個(gè)結(jié)點(diǎn)都稱為該結(jié)點(diǎn)的子孫。
第六章樹(shù)________________________________
I
t結(jié)點(diǎn)的層次:從根開(kāi)始定義,根為第一層,根的孩子為囂三盤(pán),
以此類推,即設(shè)根結(jié)點(diǎn)的層數(shù)為1,其余結(jié)點(diǎn)的層數(shù)等于其雙親結(jié)點(diǎn)的
層數(shù)加1。若某結(jié)點(diǎn)在第i層,則其孩子結(jié)點(diǎn)就在第i+1層。
樹(shù)的深度或高度:是指樹(shù)中結(jié)點(diǎn)的最大層次數(shù)。
路徑:若樹(shù)中存在一個(gè)結(jié)點(diǎn)序列瓦,k2,kj,使得ki是ki+1的
雙親(l<i<j),則稱該結(jié)點(diǎn)序列是從k]到kj的一條路徑,且路徑的長(zhǎng)
度為j-L即等于路徑上分支的數(shù)目。在樹(shù)形表示中,路徑表示從kl出
發(fā)自上而下地通過(guò)k2,k3,與各結(jié)點(diǎn)。
有序樹(shù)和無(wú)序樹(shù):若將樹(shù)中每個(gè)結(jié)點(diǎn)的各子樹(shù)看成是從左至右有序
且不能交換,則稱該樹(shù)為有序樹(shù),否則稱為無(wú)序樹(shù)。圖6.4給出了兩棵
不同的有序樹(shù)。
,森林:是指m(m>0)棵互不相交的樹(shù)的集合。
顯然,樹(shù)形結(jié)構(gòu)不同于線性結(jié)構(gòu)。在樹(shù)中,一個(gè)結(jié)點(diǎn)至多個(gè)直
接前趨(雙親),卻可以有多個(gè)直接后繼(孩子),即結(jié)點(diǎn)之間的關(guān)系不
象線性結(jié)構(gòu)中的結(jié)點(diǎn)關(guān)系是一一對(duì)應(yīng)關(guān)系,而是呈現(xiàn)出一對(duì)多的層次關(guān)系。
第六章樹(shù)
樹(shù)的基本運(yùn)算i9W
(1)setnull(T):置T為空樹(shù),即初始化一棵樹(shù)T。
(2)root(T)或root(x):求根函數(shù)。
(3)parent(T,x):求雙親函數(shù)。
(4)child(T,x,i):求孩子結(jié)點(diǎn)函數(shù)。
(5)rsibling(T,x):求右兄弟函數(shù)。
(6)create(x,F):建樹(shù)函數(shù)。
(7)delchild(x,i):子樹(shù)刪除操作。
(8)addchild(y,i,x):插入子樹(shù)操作。
(9)traverse(T):樹(shù)的遍歷操作。
第六章樹(shù)
6.2二叉樹(shù)
二叉樹(shù)(BinaryTree)是另一種重要的樹(shù)形結(jié)構(gòu),在
實(shí)際應(yīng)用中具有重要的意義。本節(jié)將詳細(xì)地討論二叉樹(shù)的
定義、重要性質(zhì)、存儲(chǔ)方式、運(yùn)算及其應(yīng)用。
第六章樹(shù)
6.2.1二叉樹(shù)的概念及運(yùn)算
1、二叉樹(shù)定義
二叉樹(shù)是n(>0)個(gè)結(jié)點(diǎn)的有限集合,這個(gè)集合可以是空集合,
或者由一個(gè)根結(jié)點(diǎn)和兩棵互不相交的分別稱為根的左子樹(shù)和右子樹(shù)
的二叉樹(shù)組成。顯然,由定義可知,二叉樹(shù)具有遞歸性質(zhì),它的特
點(diǎn)是每個(gè)結(jié)點(diǎn)至多只有二棵子樹(shù)即二叉樹(shù)中任何結(jié)點(diǎn)的度數(shù)不大于2,
而且,二叉樹(shù)的子樹(shù)有左右之分,其次序不能任意顛倒。應(yīng)該指出
的是,二叉樹(shù)與樹(shù)是兩個(gè)不同的概念,它不是樹(shù)的特殊情形,例如,
在圖6.5中,(a)和(b)所示的兩棵二叉樹(shù)雖然與(c)所示的一般
樹(shù)相似,但卻不等同于這棵一般樹(shù)。
第六章樹(shù)
(a)二叉樹(shù)1(b)二叉樹(shù)2(c)一般樹(shù)
圖6.5二叉樹(shù)與度為2的一般樹(shù)的區(qū)別舉例
第六章樹(shù)
2、二叉樹(shù)基本形態(tài)
(a)空樹(shù)(b)只有根結(jié)點(diǎn)(c)只有左子樹(shù)(d)只有右子樹(shù)(e)左
空
圖6.6二叉樹(shù)的五種基本形態(tài)
兩種特殊形態(tài)的二叉樹(shù):滿二叉樹(shù)和完全二叉樹(shù)。
第六章樹(shù)
T)滿二叉樹(shù)是指一棵深度為h且有2人1個(gè)結(jié)點(diǎn)的二叉前,笳露.7(a)
T所示是一棵深度為3的滿二叉樹(shù)。
(2)完全二叉樹(shù):對(duì)滿二叉樹(shù)中的結(jié)點(diǎn)按照從根結(jié)點(diǎn)起,自上而下,
自左至右的約定進(jìn)行連續(xù)編號(hào),一棵深度為h,有n個(gè)結(jié)點(diǎn)的二叉樹(shù),當(dāng)且
僅當(dāng)其每一個(gè)結(jié)點(diǎn)都與深度為h的滿二叉樹(shù)中的編號(hào)從1至n的結(jié)點(diǎn)一一對(duì)應(yīng)
時(shí),稱之為完全二叉樹(shù),如圖6.7(b)所示為一棵深度為3的完全二叉樹(shù),
而圖6.7(c)所示就不是完全二叉樹(shù)。
(3)滿二叉樹(shù)的每一層上具有最大的結(jié)點(diǎn)數(shù),它不存在度為1的結(jié)點(diǎn),
所有葉子結(jié)點(diǎn)均在第h層上。
(4)完全二叉樹(shù)的特點(diǎn)是所有葉子結(jié)點(diǎn)都只可能在最大的兩層出現(xiàn),
第i(i0h-l)層含有2口個(gè)結(jié)點(diǎn),第h層上的結(jié)點(diǎn)都集中在該層最左邊的位置
上,換句話說(shuō),完全二叉樹(shù)上的結(jié)點(diǎn)編號(hào)與同深度的滿二叉樹(shù)對(duì)應(yīng)位置的
結(jié)點(diǎn)編號(hào)相同。滿二叉樹(shù)是完全二叉樹(shù)的特殊情形,它一定是完全二叉樹(shù),
而完全二叉樹(shù)不一定是滿二叉樹(shù)。
第六章樹(shù)
(c)非完全二叉樹(shù)
第六章樹(shù)
二叉樹(shù)的基本運(yùn)算
(1)setnull(bt):置bt為空二叉樹(shù)-
(2)求根函數(shù)root(bt)或root(x)(3)求雙親函數(shù)parent(bt,x)
(4)求孩子結(jié)點(diǎn)函數(shù)Ichiki(bt,x)和rchild(bt,x)
(5)插入運(yùn)算addlchild(b,x,y)和addrchild(bt,x,y)
(6)二叉樹(shù)建立運(yùn)算create(x,Ibt,rbt)
(7)刪除子樹(shù)運(yùn)算dellchild(bt,x)和delrchild(bt,x)
(8)遍歷運(yùn)算traverse(bt)
第六章樹(shù)
6.2.2二叉樹(shù)的性質(zhì).
性質(zhì)1在二叉樹(shù)的第i層上至多有2H結(jié)點(diǎn)(應(yīng)1)。
性質(zhì)2深度為h的二叉樹(shù)至多有2?1個(gè)結(jié)點(diǎn)(h>l)o
性質(zhì)3對(duì)任何一棵二叉樹(shù)T,如果其終端結(jié)點(diǎn)數(shù)為%,度為2的結(jié)點(diǎn)數(shù)為嗎,
則n0=n2+lo
性質(zhì)4具有n個(gè)結(jié)點(diǎn)的完全二叉樹(shù)的深度為|_log2n」+l。
性質(zhì)5如果對(duì)一棵有n個(gè)結(jié)點(diǎn)的完全二叉樹(shù)(其深度為,按照
從根結(jié)點(diǎn)起,自上而下,從左到右的約定對(duì)所有結(jié)點(diǎn)從1到n進(jìn)行編號(hào),
則對(duì)于任意的編號(hào)為i的結(jié)點(diǎn)(l<i<n)有以下性質(zhì):
(1)如果i=L則結(jié)點(diǎn)i是二叉樹(shù)的根,無(wú)雙親;如果i>l,則其雙親的
編號(hào)是㈤2」。
(2)如果2i>n,則結(jié)點(diǎn)i無(wú)左孩子(結(jié)點(diǎn)i為葉子結(jié)點(diǎn)),否則其左孩子
的編號(hào)是2i。
(3)如果2i+l>n,則結(jié)點(diǎn)i無(wú)右孩子,否則其右孩子的編號(hào)是2i+L
(4)若i為奇數(shù)且不為1,則該結(jié)點(diǎn)左兄弟的編號(hào)是i?L否則無(wú)左兄弟。
(5)若i為偶數(shù)且小于n,則該結(jié)點(diǎn)右兄弟的編號(hào)是i+L否則無(wú)右兄弟。
第六章樹(shù)
J|623二叉樹(shù)的存儲(chǔ)結(jié)構(gòu)
1.順序存儲(chǔ)結(jié)構(gòu)
二叉樹(shù)的順序存儲(chǔ)是用一組地址連續(xù)的存儲(chǔ)單元存儲(chǔ)二叉樹(shù)中的數(shù)
據(jù)元素。
(1)完全二叉樹(shù)
對(duì)一棵具有n個(gè)結(jié)點(diǎn)的完全二叉樹(shù),從樹(shù)根結(jié)點(diǎn)起,自上層到下層,
每層自左至右地給所有結(jié)點(diǎn)編號(hào),然后將完全二叉樹(shù)中的所有結(jié)點(diǎn)按編
號(hào)順序依次存儲(chǔ)在一維數(shù)組R[L..n]中,如圖6.8(a)所示。
(2)一般二叉樹(shù)
一般二叉樹(shù)也必須按完全二叉樹(shù)的形式來(lái)存儲(chǔ)一般二叉樹(shù)中的結(jié)點(diǎn),
只有通過(guò)添加一些并不存在的“虛結(jié)點(diǎn)”,使之成為完全二叉樹(shù)的形式
才行,如圖6.8(b)所示。
在最壞的情況下,一個(gè)深度為h且只有h個(gè)結(jié)點(diǎn)的右單支樹(shù)需要2L1
個(gè)的結(jié)點(diǎn)空間。所以,不宜采用順序存儲(chǔ)結(jié)構(gòu)存儲(chǔ)一般的二叉樹(shù)。
A#B###C
(b)一般二叉樹(shù)及其順序存儲(chǔ)結(jié)構(gòu)
圖6.8二叉樹(shù)的編號(hào)及其順序存儲(chǔ)結(jié)構(gòu)
!第六章樹(shù)
2.鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),?N^
1(1)二叉鏈表
采用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)來(lái)存儲(chǔ)二叉樹(shù),而且設(shè)計(jì)不同的結(jié)點(diǎn)結(jié)構(gòu)可以構(gòu)
成不同形式的二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)。二叉樹(shù)的結(jié)點(diǎn)由一個(gè)數(shù)據(jù)元素
和分別指向其左、右子樹(shù)的兩個(gè)分支構(gòu)成,所以,二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)
結(jié)構(gòu)中的結(jié)點(diǎn)至少應(yīng)包含三個(gè)域:數(shù)據(jù)域和左、右指針域,即每個(gè)結(jié)
點(diǎn)應(yīng)包含兩個(gè)指針I(yè)child和rchild,分別指向該結(jié)點(diǎn)的左孩子和右孩子。
其結(jié)點(diǎn)結(jié)構(gòu)形式如圖6.9所示。
Ichilddatarchild
圖6.9二叉鏈表結(jié)點(diǎn)結(jié)構(gòu)
第六章樹(shù)
結(jié)點(diǎn)類型定義:
typedefstructnode
{datatypedata;/*數(shù)據(jù)域*/
structnode*lchild,*rchild;/*左、右孩子域*/
}btnode,*bitree;
在一棵二叉樹(shù)中,所有類型為btnode的結(jié)點(diǎn),加上一個(gè)指向
根結(jié)點(diǎn)的頭指針,就可構(gòu)成二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),有時(shí)將這種
存儲(chǔ)結(jié)構(gòu)稱為二叉鏈表,如圖6.10所示。一個(gè)二叉鏈表可以由頭
指針唯一地確定。
采用二叉鏈表作為二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)便于從根結(jié)點(diǎn)開(kāi)始
往下搜索孩子或子孫結(jié)點(diǎn)。
第六章樹(shù)
root
(a)二叉樹(shù)(b)二叉鏈表
圖6.10二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)
第六章樹(shù)
(3)三叉鏈表
有時(shí),為了便于檢索結(jié)點(diǎn)的雙親或祖先結(jié)點(diǎn),可在結(jié)點(diǎn)中
增加一個(gè)指向其雙親結(jié)點(diǎn)的指針域(如圖6.11(a)中的parent),這
種結(jié)構(gòu)稱為三叉鏈表,如圖6.11所示即為圖6.10(a)中二叉樹(shù)所對(duì)應(yīng)
的三叉鏈表。
(a)三叉鏈表結(jié)點(diǎn)結(jié)構(gòu)(b)三叉鏈表
圖6.11二叉樹(shù)的三叉鏈表
第六章樹(shù)
二叉樹(shù)的簡(jiǎn)單運(yùn)算實(shí)現(xiàn)
這里所討論的運(yùn)算實(shí)現(xiàn)算法,以二叉鏈表作為其存儲(chǔ)結(jié)構(gòu)。
(1)置空二叉樹(shù)setnun(bt)
voidsetnull(bitreebt)
{bt->lchild=NULL;/*左鏈域置空*/
bt->rchild=NULL;/*右鏈域置空刃
}
(2)求二叉樹(shù)的根root(bt)
datatyperoot(bitreebt)
{if(bt->lchild==NULL)
returnNULL;/*空樹(shù)時(shí)返回NULL*/
else
return(bt->lchild->data);/*否則返回根結(jié)點(diǎn)數(shù)據(jù)域的值*/
)
[第六章樹(shù).
(3)建立二叉樹(shù)操作create(x,Ibt,rbt)
bitreecreate(datatypex,bitreeIbt,bitreerbt)
{bitreep;
p=(bitree)malloc(sizeof(btnode));
/*申請(qǐng)一個(gè)結(jié)點(diǎn)空間,地址傳給p指針*/
p->data=x;
p->lchild=lbt;/*把二叉樹(shù)Ibt填入p的左孩子鏈域*/
p->rchild=rbt;/*把二叉樹(shù)rbt填入p的右孩子鏈域*/
returnp;/*返回建成的二叉樹(shù)*/
)
(4)插入左孩子addlchild(bt,x)
voidaddlchild(bitreebt,datatypex)
{bitreep;
p=(bitree)malloc(sizeof(btnode));/*申請(qǐng)一個(gè)結(jié)點(diǎn)空間*/
p->data=x;
p->lchild=NULL;
p->rchild=NULL;/*左、右孩子域置空*/
第六章樹(shù)
(5)刪除左孩子dellchild(bt)
voiddellchild(bitreebt)
{bitreep;
p=bt->lchild;/*保存左子樹(shù)指針*/
bt->lchild=NULL;/*bt的左孩子域置空*/
free(p);/*釋放左子樹(shù)空間*/
第六章樹(shù)
6.3遍歷二叉樹(shù)
在實(shí)際應(yīng)用中,常常要求在二叉樹(shù)中檢索或查找具有某種特征的
結(jié)點(diǎn),或者對(duì)二叉樹(shù)中的所有結(jié)點(diǎn)逐一地進(jìn)行某種處理,這就提出了
一個(gè)遍歷二叉樹(shù)的問(wèn)題,即如何按某條搜索路徑巡訪二叉樹(shù)中的每個(gè)
結(jié)點(diǎn),使得每個(gè)結(jié)點(diǎn)都被訪問(wèn)且僅被訪問(wèn)一次??梢哉f(shuō),遍歷操作的
實(shí)質(zhì)就是使非線性結(jié)構(gòu)線性化。
若以L、D、R分別表示遍歷左子樹(shù)、訪問(wèn)根結(jié)點(diǎn)和遍歷右子樹(shù),
貝I」有DLR、LDR、LRD、DRL、RDL和RLD六種遍歷次序。顯然,前
三種遍歷次序和后三種是對(duì)稱的,若約定先左后右,則只有前三種情
況即DLR、LDR和LRD,分別稱為前序遍歷、中序遍歷和后序遍歷。
■第六章樹(shù)._______
6.3.1遍歷二叉樹(shù)的遞歸算法—
假設(shè)二叉樹(shù)采用二叉鏈表作為存儲(chǔ)結(jié)構(gòu),對(duì)根結(jié)點(diǎn)的訪問(wèn)是輸出結(jié)點(diǎn)數(shù)
據(jù),以上三種遍歷運(yùn)算的遞歸定義及算法如下:
L前序遍歷(PreorderTraversal)
若二叉樹(shù)為空,則遍歷結(jié)束,否則進(jìn)行如下操作:
(1)訪問(wèn)根結(jié)點(diǎn);
(2)前序遍歷根結(jié)點(diǎn)的左子樹(shù);
(3)前序遍歷根結(jié)點(diǎn)的右子樹(shù)。
前序遍又稱之為先根遍歷或先序遍歷。其遞歸算法描述如下:
voidpreorder(bitreebt)
{if(bt)
{printf(“%d\t”,bt->data);/*訪問(wèn)根結(jié)點(diǎn),這里假設(shè)數(shù)據(jù)域?yàn)檎?/
preorder(bt->lchild);/*前序遍歷左子樹(shù)*/
preorder(bt->rchild);/*前序遍歷右子樹(shù)刃
)
)
第六章樹(shù)
2.中序遍歷(InorderTraversal)
若二叉樹(shù)為空,則遍歷結(jié)束,否則進(jìn)行如下操作:
(1)中序遍歷左子樹(shù);
(2)訪問(wèn)根結(jié)點(diǎn);
(3)中序遍歷右子樹(shù)。
中序遍歷又稱為中根遍歷。算法描述如下:
voidinorder(bitreebt)
{if(bt)
{inorder(bt->lchild);/*中序遍歷左子樹(shù)*/
printf(“%d\t”,bt->data);/*訪問(wèn)根結(jié)點(diǎn)*/
inorder(btt->rchild);/*市序遍歷右子樹(shù)*/
)
}
3,后序遍歷(PostorderTraversal)
若二叉樹(shù)為空,則遍歷結(jié)束,否則進(jìn)行如下操作:
(1)后序遍歷左子樹(shù);
(2)后序遍歷右子樹(shù);
(3)訪問(wèn)根結(jié)點(diǎn)。.,
第六章樹(shù)
,后序遍歷也稱為后根遍歷。其遞歸算法描述如下:’
voidpostorder(bitreebt)
{if(bt)
{postorder(bt->lchild);/*后序遍歷左子樹(shù)*/
postorder(bt->rchild);/*后序遍歷右子樹(shù)*/
printf("%d\t”,bt->data);/*訪問(wèn)根結(jié)點(diǎn)*/
}
}
從遍歷遞歸算法的執(zhí)行蹤跡來(lái)看,這三種遍歷的搜索路線相同,如圖
6.12所示。只要分別將搜索路線上的所有在第一次、第二次和第三次經(jīng)
過(guò)的結(jié)點(diǎn)收集,即可分別得到該二叉樹(shù)的前序、中序和后序遍歷序列。
第六章樹(shù)
(a)遍歷二叉樹(shù)的搜索路線(b)遍歷二叉樹(shù)的的遞歸執(zhí)行過(guò)程
圖6.12遍歷過(guò)程示意圖
■第六章樹(shù).______
*叉樹(shù)的三種遍歷序列如下:.0
前序遍歷序列:ABDCE
中序遍歷序列:DBACE
后序遍歷序列:DBECA
又如,一棵表達(dá)式二叉樹(shù)如圖6.13所示,對(duì)該表達(dá)式樹(shù)進(jìn)行前序、中
序和后序遍歷,結(jié)果分別為:
前序遍歷序列:-+a*bc/de
中序遍歷序列:a+b*c-d/e
后序遍歷序列:abc*+de/?
上述三種遍歷序列都是線性序列,有一個(gè)開(kāi)始結(jié)點(diǎn)和一個(gè)終端結(jié)點(diǎn),
其余結(jié)點(diǎn)有且僅有一個(gè)前趨結(jié)點(diǎn)和一個(gè)后繼結(jié)點(diǎn)。有時(shí),為了區(qū)分樹(shù)形
結(jié)構(gòu)中的前趨結(jié)點(diǎn)和后繼結(jié)點(diǎn)的概念,對(duì)以上三種線性序列,均在某結(jié)
點(diǎn)的前趨和后繼之前加上其遍歷次序的名稱。
13表注式樹(shù)
第六章樹(shù)
632遍歷二叉樹(shù)的非遞歸算法
遞歸算法簡(jiǎn)潔精煉、可讀性好、易理解,但其執(zhí)行效率較低,但
有些程序設(shè)計(jì)語(yǔ)言不支持遞歸功能,所以,我們有必要討論遍歷二叉樹(shù)
的非遞歸算法。
可以利用后來(lái)保存遍歷過(guò)程中遍歷的結(jié)點(diǎn)的左孩子和右孩子,從而
實(shí)現(xiàn)遍歷二叉樹(shù)的非遞歸算法。假定在每個(gè)算法中,s為用一維數(shù)組表
示的順序棧,top為棧頂指針,P為臨時(shí)變量,S棧的作用是保存待訪問(wèn)
結(jié)點(diǎn)的指針,S棧的深度要大于整個(gè)樹(shù)的深度,即假設(shè)??臻g足夠大,
不會(huì)出現(xiàn)棧滿清況。
I第六章樹(shù)—
卜序遍歷二叉樹(shù)的非遞歸算法
#defineM100.
voidpreorder(bitreebt)/*前序遍歷二叉樹(shù)的非遞歸算法*/
{bitreep,s[M];
inttop=-l;
p=bt;
do
{while(p)
{printf("%d\t”,p->data);
if(p->rchild)
s[++top]=p->rchild;
)
if(top>=0)/*棧非空,退棧,使p指向右子樹(shù)繼續(xù)掃描右子樹(shù)*/
p=s[top-];
}while((top==-1)&&(p==NULL));
I第六章樹(shù)
2.中序遍歷二叉樹(shù)的非遞歸算法
voidinorder(bitreebt)/*中序遍歷二叉樹(shù)的非遞歸算法*/
{bitreep,s[M];
inttop=-l;
p=bt;
do
{while(p)/*搜索最左下的結(jié)點(diǎn),并將左孩子進(jìn)棧*/
{s[++top]=p;
p=p->lchild;
)
if(top>=0)
{p=s[top-];/*出棧,棧頂元素賦p*/
printf(“%d\t”,p->data);/*訪問(wèn)根結(jié)點(diǎn)*/
p=p->rchild;/*p指向右子樹(shù),繼續(xù)搜索右子樹(shù)*/
)
}while((top==-1)&&(p==NULL));
第六章樹(shù)—
]3,后序遍歷二叉樹(shù)的非遞歸算法?
voidpostorder(bitreebt)/*后序遍歷二叉樹(shù)的非遞歸算法*/
{ints2[M],top=-l,flag;
bitreep,sl[M];
p=bt;
do
{while(p)/*遍歷其左子樹(shù)*/
{sl|++topl=p;
s2[top]=0;/*p結(jié)點(diǎn)首次進(jìn)棧*/
p=p->lchild;
)
if(top>=0)
{flag=s2[--top];
p=sl[top];
第六章樹(shù)
if(flag==0)
{sl[top]=p;'
Ts2[++top]=l;/*p結(jié)點(diǎn)第二次進(jìn)棧*/
p=p->rchild;
}/*遍歷p結(jié)點(diǎn)的右子樹(shù)*/
else
{printf(w%d\f\p->data);/*訪問(wèn)根結(jié)點(diǎn)*/
p=NULL;
}
)
}while(top==-1);
)
后序遍歷的非遞歸算法也可以描述如下:
voidpostorder(bitreebt)/*后序遍歷二叉樹(shù)的非遞歸算法*/
{inttop=-l;
bitree^[M];_____________
第六章樹(shù)—
do
{while(p)
{top++;
s[top]=p;
if(p->lchild!=NULL)p=p->lchild;
elsep=p->rchild;
)
p=s[top];
top—;
printf("%d\t",p->data);/*訪問(wèn)結(jié)點(diǎn)*/
while((top>=0)&&(s[top]->rchild==p))
{P=s[top];
top-
printf(66%d\tM,p->data);
)
if(top>=0)p=s[top]->rchild;
}while(top==-l);
■第六章樹(shù)
T6.3.3二叉樹(shù)的層次遍歷
所謂層次遍歷(LevelorderTraversal)是指從二叉樹(shù)的根結(jié)點(diǎn)開(kāi)始
從上到下逐層遍歷二叉樹(shù),在同一層次中從左到右依次訪問(wèn)各個(gè)結(jié)點(diǎn)。
例如,對(duì)圖6.12(a)的二叉樹(shù),按層次遍歷得到的結(jié)點(diǎn)序列為ABCDE。
可利用一個(gè)隊(duì)列結(jié)構(gòu)來(lái)實(shí)現(xiàn)層次遍歷,其做法是:
(1)首先將根結(jié)點(diǎn)入隊(duì)列;
(2)當(dāng)隊(duì)列不空,從隊(duì)列中取出隊(duì)頭結(jié)點(diǎn)訪問(wèn)它,并在其左右孩子非
空時(shí),把它的左孩子和右孩子結(jié)點(diǎn)依次入隊(duì)列;(3)反復(fù)執(zhí)行(2),
直到隊(duì)列為空時(shí)止。
第六章樹(shù)
#defineMAXSIZE100
voidlevelorder(bitreebt)/*層次遍歷二叉樹(shù)bt*/
{bitreequeue[MAXSIZE];/*定義隊(duì)列*/
intfront,rear;/*定義隊(duì)列指針*/
if(bt==NULL)/*如果是空樹(shù),則返回*/
return;
front=0;rear=0;/*隊(duì)列指針初始化*/
queue[++rear]=bt;/*根結(jié)點(diǎn)入隊(duì)*/
while(front!=rear)/*當(dāng)隊(duì)列不空*/
{front=(front+l)%MAXSIZE;/*隊(duì)頭結(jié)點(diǎn)出隊(duì)*/
printf("%d\t",queue[front]->data);
if(queue[front]->lchild!=NULL)
{rear=(rear+l)%MAXSIZE;/*修改隊(duì)尾指針*/
queue[rear]=queue[front]->lchild;
}
if(queue[front]->rchild!=NULL)
{rear=(rear+l)%MAXSIZE;/*修改隊(duì)尾指針*/
queuefrear]=queue[front]->rchild;
第六章樹(shù)
6.3.4二叉樹(shù)的運(yùn)算舉例
遍歷是二叉樹(shù)各種運(yùn)算的基礎(chǔ),利用各種遍歷運(yùn)算可以在遍
歷過(guò)程中對(duì)結(jié)點(diǎn)進(jìn)行各種操作,如求二叉樹(shù)中某結(jié)點(diǎn)的雙親、孩
子和結(jié)點(diǎn)的層次等,也可以在遍歷過(guò)程中生成結(jié)點(diǎn),建立二叉樹(shù)
的存儲(chǔ)結(jié)構(gòu)以及輸出二叉樹(shù)等。
第六章樹(shù)
艮建立二叉樹(shù)
例如,若要建立圖6.14所示的二叉樹(shù)的二叉鏈表,則按下列順序
輸入字符:AB(|)D(|)(|)C(|)(|)(其中巾表示空格字符,說(shuō)明無(wú)子樹(shù))。顯然,
該輸入序列與二叉樹(shù)的前序遍歷序列相對(duì)應(yīng)。算法描述如下:
bitreecreatebitree()
{bitreet;charch;
scanf(“%c”,&ch);
if(ch==69)t=NULL;
else
{t=(bitree)malloc(sizeof(btnode));/*生成根結(jié)點(diǎn)*/
t->data=ch;
t->lchild=createbitree();/*建立左子樹(shù)*/
t->rchild=createbitree();/*建立右子樹(shù)*/
)
return(t);
)
第六章樹(shù)
r一
上20t
/IA|\
一/???
AB\AcA
?、一
八|D|八
(a)二叉樹(shù)(b)二叉鏈表
圖6.14二叉樹(shù)及其二叉鏈表
第六章樹(shù)
2.求二叉樹(shù)的葉子數(shù)目
可以在遍歷過(guò)程中對(duì)所遇結(jié)點(diǎn)判斷是否為葉子結(jié)點(diǎn),若是則統(tǒng)計(jì)變
量加1,直到遍歷完所有結(jié)點(diǎn),葉子結(jié)點(diǎn)總數(shù)即可求得。下面給出利用中
序遍歷求葉子結(jié)點(diǎn)數(shù)的遞歸算法:
intcountleaf(bitreebt)
{intnum=O;/*初始化統(tǒng)計(jì)變量*/
if(bt!=NULL)
if((bt->lchild==NULL)&&(bt->rchild==NULL))
num++;
else
num=countleaf(bt->lchild)+countleaf(bt->rchild);
returnnum;
)
■第六章樹(shù).______
翼叉樹(shù)中結(jié)點(diǎn)的檢索
以前序遍歷來(lái)實(shí)現(xiàn)檢索運(yùn)算的遞歸算法。
bitreesearch(bitreebt,datatypex)
{if(bt!=NULL)/*如果二叉樹(shù)bt非空刃
{if(bt->data==x)returnbt;/*如果根結(jié)點(diǎn)數(shù)據(jù)域值為x則返回bt*/
search(bt->lchild,x);/*在左子樹(shù)中檢索*/
search(bt->rchild,x);/*在右子樹(shù)中檢索*/
)
else
returnNULL;
)
第六章樹(shù)
4.求二叉樹(shù)的高度
利用后序遍歷求二叉樹(shù)高度的遞歸算法:
inttreedepth(bitreebt)
{inth,Ih,rh;
if(bt==NULL)h=0;
else
{lh=treedepth(bt->lchild);
rh=treedepth(bt->rchild);
if(lh>=rh)h=lh+l;
elseh=rh+l;
)
returnh;
第六章樹(shù)
6.4線索二叉樹(shù)
B?線索二叉樹(shù)的概念
1、問(wèn)題提出
遍歷二叉樹(shù)可以得到二叉樹(shù)中結(jié)點(diǎn)的某個(gè)遍歷次序序列,這實(shí)質(zhì)上是
對(duì)一個(gè)非線性結(jié)構(gòu)進(jìn)行線性化的操作,使得除第一個(gè)和最后一個(gè)外的每個(gè)
結(jié)點(diǎn)在這些線性序列中有且僅有一個(gè)直接前趨和直接后繼。然而,當(dāng)二叉
樹(shù)以二叉鏈表作為存儲(chǔ)結(jié)構(gòu)時(shí),由于每個(gè)結(jié)點(diǎn)中只有指向其左、右孩子的
指針,所以,從任一個(gè)結(jié)點(diǎn)出發(fā)可以直接找到該結(jié)點(diǎn)的左、右孩子結(jié)點(diǎn),
在一般情況下是不能直接得到該結(jié)點(diǎn)在某一遍歷序列中的前趨和后繼結(jié)點(diǎn)
的信息。那如何才能直接得到這些信息呢?
2、解決辦法
(1)通過(guò)采用多重鏈表來(lái)表示二叉樹(shù)的方法得到,即在每個(gè)結(jié)點(diǎn)中除
原來(lái)的左、右孩子的指針之外,增加兩個(gè)指針指示結(jié)點(diǎn)在某一個(gè)遍歷序列
中的前趨和后繼結(jié)點(diǎn)。
第六章樹(shù)
(2)通過(guò)遍歷的方法,每當(dāng)要求某結(jié)點(diǎn)在某一個(gè)遍歷序列中的前趨和
后繼結(jié)點(diǎn)的信息,就進(jìn)行一次遍歷。
(3)利用在有n個(gè)結(jié)點(diǎn)的二叉鏈表中的n+1個(gè)是空鏈域來(lái)存放結(jié)點(diǎn)在
某一個(gè)遍歷序列中的前趨和后繼結(jié)點(diǎn)的指針。
3、線索二叉樹(shù)
有時(shí)也裝種附加的指向其前趨和后繼的指針?lè)Q為線索(Thread),而
將加上了線索的二叉鏈表稱為線索鏈表(ThreadLinkedList),相應(yīng)的
加上線索的二叉樹(shù)稱為線索二叉樹(shù),對(duì)二叉樹(shù)以某種次序遍歷使其變?yōu)榫€
索二叉樹(shù)的過(guò)程稱為線索化。
第六章樹(shù)
線索二叉鏈表的類型:
typedefenum{0,1}ptrtag;
typedefstructbithnode
{datatypedata;
structbithnode*lchild,*rchild;
ptrtagItag,rtag;/*標(biāo)志域*/
}bithnode,*bithptr;
其中:ltag=0表示Ichild域?yàn)橹赶蚪Y(jié)點(diǎn)的左孩子的指針;ltag=l表示
Ichild域?yàn)橹赶蚪Y(jié)點(diǎn)其前趨的左線索;rtag=0表示rchild域?yàn)橹赶蚪Y(jié)點(diǎn)的右
孩子的指針;rtag=l表示rchild域?yàn)橹赶蚪Y(jié)點(diǎn)其后繼的右線索。例如圖
6.15(a)、(b)所示。
第六章樹(shù)
(a)中序線索二叉樹(shù)(b)中序線索鏈表
圖6.15中序線索二叉樹(shù)及其線索鏈表
第六章樹(shù)
642線索二叉鏈表的建立
可以在對(duì)二叉樹(shù)的某種次序遍歷過(guò)程中,一邊遍歷一邊建立線索,
若當(dāng)前訪問(wèn)結(jié)點(diǎn)的左孩子域?yàn)榭談t建立前趨線索,若右孩子域?yàn)榭談t
建立后繼線索。下面給出中序線索二叉鏈表的建立算法。
要建立中序線索二叉鏈表,可以對(duì)二叉樹(shù)采用一邊中序遍歷一邊
建立線索的方法,若在遍歷過(guò)程中被訪問(wèn)結(jié)點(diǎn)的左孩子為空,則建立
前趨線索;若右孩子為空,則建立后繼線索。算法描述如下:
第六章樹(shù)
bithptrpre/*pre為全程量,初值為NULL*/
bithptrcreatinordthrd(bithptrroot)/*t指向二叉樹(shù)的根*/
{voidinthrd();
bithptrthrt;
thrt=(bithrtree)malloc(sizeof(bithrnode));
thrt->ltag=O;
thrt->rtag=l;
thrt->rchild=thrt;
if(root==NULL)
thrt->lchild=thrt;
else
{thrt->lchild=root;
pre=thrt;
inthrd(root);/*進(jìn)行中序線索化*/
pre->rchild=thrt;
pre->rtag=l;
thre->rchild=pre;
)
returnthrt;—一
1—
第六章樹(shù)
voidinthrd(bithptrroot)/*將二叉樹(shù)root中序線索化*/
{if(root!=NULL)
{inthrd(root->lchild);/*左子樹(shù)線索化*/
if(root->lchild==NULL)root->ltag=l;/*建立左線索標(biāo)志*/
if(root->rchild==NULL)root->rtag=l;/*建立右線索標(biāo)志*/
if(pre!=NULL)/*pre為全程量,為root的前趨指針*/
{if(pre->rtag==1)
pre->rchild=root;/*pre無(wú)右子樹(shù)*/
if(root->ltag==1)
root->lchild=pre;
}
pre=root;
inthrd(root->rchild);/*右子樹(shù)線索化*/
第六章樹(shù)
■6.4.3遍歷線索二叉樹(shù)蕓—
?在線索二叉樹(shù)上進(jìn)行遍歷,只要從頭結(jié)點(diǎn)出發(fā)反復(fù)查找結(jié)點(diǎn)前繼,
直到又回到頭結(jié)點(diǎn)時(shí)止。下面給出中序遍歷中序線索二叉樹(shù)的算法。
voidinordtraverse(bithptrroot)/*root為頭結(jié)點(diǎn)指針*/
{bithptrp;
p=root->lchild;/*p指向根結(jié)點(diǎn)*/
while(p!=root)/*空樹(shù)或遍歷結(jié)束時(shí),p=root*/
{while(p->ltag==0)/*查找最左下的結(jié)點(diǎn)*/
p=p->lchild;
printf(66%c\tM,p->data);
while((p->rtag==1)&&(p->rchild!=root))
{p=p->rchild;/*若右指針為線索,貝傳遞指針*/
printf("%c\t",p->data);/*訪問(wèn)結(jié)點(diǎn)*/
)
p=p->rchild;
)
<Back
第六章樹(shù)
iI6.5樹(shù)和森林
6.5.1樹(shù)的存儲(chǔ)結(jié)構(gòu)
1.雙親表示法
可以在存儲(chǔ)樹(shù)中結(jié)點(diǎn)信息的同時(shí),為每個(gè)結(jié)點(diǎn)增加一個(gè)指向其雙親
的指針parent。假設(shè)以一組地址連續(xù)的空間存儲(chǔ)樹(shù)的結(jié)點(diǎn),則其類型說(shuō)
明如下:
#defineMAXSIZE100
typedefstructnode
{datatypedata;
intparent;
Jptnode;
ptnodeT[MAXSIZE];
第六章樹(shù)
.
0123456789???maxsize-1
dataABCDEFGHI???
parent-1011122244???
(a)樹(shù)(b)雙親表示
圖6.16樹(shù)的雙親表示
第六章樹(shù)
2.孩子表示法
為樹(shù)中每個(gè)結(jié)點(diǎn)的孩子建立一個(gè)單鏈表,一棵具有n個(gè)結(jié)點(diǎn)的樹(shù)就有
n個(gè)孩子鏈表,并在每個(gè)結(jié)點(diǎn)中增加一個(gè)指針域,指向其孩子鏈表的表頭,
這種孩子表示法也稱為孩子鏈表表示法,其形式說(shuō)明如下:
typedefstructnode
{datatypedata;
structnode*next;/*定義孩子鏈表頭指針*/
}ctree;
ctreeT[MAXSIZE];
孩子表示法便于實(shí)現(xiàn)對(duì)結(jié)點(diǎn)的孩子的運(yùn)算,但不適合于對(duì)結(jié)點(diǎn)的雙
親進(jìn)行運(yùn)算。若要既便于實(shí)現(xiàn)涉及孩子又便于實(shí)現(xiàn)與雙親有關(guān)的運(yùn)算,
可以考慮將雙親表示法與孩子鏈表表示法結(jié)合起來(lái),形成雙親孩子鏈表
表不法。
第六章樹(shù)
1D人
2G人
3
4
5
6
7
8
9
圖6.17樹(shù)的孩子鏈表表示
第六章樹(shù)
1
2
3
4
5
6
7
8
9
圖6.18樹(shù)的雙親孩子鏈表表示
第六章樹(shù)
?孩子兄弟表示法
該方法又稱二叉鏈表表示法,即以二叉鏈表做為樹(shù)的存儲(chǔ)結(jié)構(gòu),
鏈表中結(jié)點(diǎn)的兩個(gè)指針域分別指向結(jié)點(diǎn)的第一個(gè)孩子結(jié)點(diǎn)和下一個(gè)右
兄弟結(jié)點(diǎn),所以,有時(shí)也稱為左孩子右兄弟表示法。其結(jié)構(gòu)的類型說(shuō)
明如下:
typedefstructnode
{datatypedata;
structnode*firstchild,*nextsib;
}cstnodc?*cstree;
利用這種存儲(chǔ)結(jié)構(gòu)廟于實(shí)現(xiàn)樹(shù)的各種運(yùn)算如查找結(jié)點(diǎn)的孩子等,
可借助二叉鏈表導(dǎo)出樹(shù)與二叉樹(shù)之間的確定對(duì)應(yīng)關(guān)系,并利用二叉樹(shù)
的有關(guān)算法來(lái)實(shí)現(xiàn)對(duì)樹(shù)的各種運(yùn)算。
第六章樹(shù)
圖6.19樹(shù)的孩子兄弟表示法
第六章樹(shù)
6.5.2樹(shù)、森林與二叉樹(shù)的轉(zhuǎn)換
可借助二叉鏈表導(dǎo)出樹(shù)與二叉樹(shù)之間的確定對(duì)應(yīng)關(guān)系。任何一個(gè)
森林或一棵樹(shù)可以唯一地對(duì)應(yīng)于一棵二叉樹(shù),而任何一棵二叉樹(shù)也能
唯一■地對(duì)應(yīng)到一■個(gè)森林或一1棵樹(shù)上。
第六章樹(shù)
■L樹(shù)、森林轉(zhuǎn)換為二叉樹(shù)、》一,
「從樹(shù)的孩子兄弟表示法中可以導(dǎo)出樹(shù)與二叉樹(shù)的對(duì)應(yīng)關(guān)系,的樹(shù)中
每個(gè)結(jié)點(diǎn)最多只有一個(gè)最左邊的孩子和一個(gè)右鄰的兄弟,按照這種關(guān)系,
就可以將一棵樹(shù)轉(zhuǎn)換為二叉樹(shù)。
圖6.20樹(shù)轉(zhuǎn)換為二叉樹(shù)
森林轉(zhuǎn)換為二叉樹(shù):先將森林中的每一棵樹(shù)轉(zhuǎn)換為二叉樹(shù),再將第一
棵樹(shù)的樹(shù)根作為轉(zhuǎn)換后二叉樹(shù)的根,第一棵樹(shù)的左子樹(shù)作為轉(zhuǎn)換后二叉
樹(shù)的左子樹(shù),第二棵樹(shù)作為轉(zhuǎn)換后的二叉樹(shù)的右子樹(shù),第三棵樹(shù)作為轉(zhuǎn)
如此進(jìn)行,直紗轉(zhuǎn)臉宅:上匕
第六章樹(shù)
AEA
森林與二叉樹(shù)轉(zhuǎn)換
CDFHE
C
樹(shù)與二叉樹(shù)轉(zhuǎn)換
DH
E
I
H
K
C
K
圖6.21樹(shù)、森林與二叉樹(shù)的相互轉(zhuǎn)換示意圖
第六章樹(shù)
?二叉樹(shù)轉(zhuǎn)換成森林
若二叉樹(shù)非空,則將二叉樹(shù)的根及其左子樹(shù)作為轉(zhuǎn)換后的第一棵樹(shù)的
二叉樹(shù)形式,剩下的二叉樹(shù)的右子樹(shù)又可以看作是由一個(gè)森林轉(zhuǎn)換后的二
叉樹(shù),可以利用同樣的方法進(jìn)行轉(zhuǎn)換,如此類推,直到最后產(chǎn)生一棵沒(méi)有
右子樹(shù)的二叉樹(shù)為止,這樣就得到了森林。
若想進(jìn)一步得到樹(shù),可以利用樹(shù)的孩子兄弟表示法的逆方法,即根據(jù)
結(jié)點(diǎn)本身、結(jié)點(diǎn)的右孩子、右孩子的右孩子、…,原本都是同一個(gè)雙親的
兄弟這個(gè)性質(zhì)將二叉樹(shù)轉(zhuǎn)換為樹(shù)。
顯然,上述定義是遞歸定義,容易寫(xiě)出相互轉(zhuǎn)換的遞歸算法。同時(shí),
利用樹(shù)、森林與二叉樹(shù)的相互轉(zhuǎn)換,對(duì)樹(shù)和森林的運(yùn)算也可轉(zhuǎn)換成二叉樹(shù)
的運(yùn)算來(lái)實(shí)現(xiàn)。
第六章樹(shù)
?3樹(shù)和森林的遍歷
對(duì)于樹(shù)和森林,根據(jù)訪問(wèn)根結(jié)點(diǎn)的次序可分為前序遍歷和后序遍歷
兩種方法。
L樹(shù)的遍歷
(1)樹(shù)的前序遍歷
樹(shù)的前序遍歷也稱作先根遍歷或先序遍歷,其遞歸定義為:
若樹(shù)非空,則先訪問(wèn)樹(shù)的根結(jié)點(diǎn),然后依次前序遍歷根的各棵子樹(shù)。
(2)樹(shù)的后序遍歷
樹(shù)的后序遍歷也稱作后根遍歷,其遞歸定義為:
若樹(shù)非空,則先依次后序遍歷根的各棵子樹(shù),然后訪問(wèn)根結(jié)點(diǎn)。
例如,對(duì)圖6.16(a)中所示的樹(shù)進(jìn)行先序遍歷,可得前序遍歷序列
為:ABEFGCDHI
若對(duì)其進(jìn)行后序遍歷,則可得后序遍歷序列為:EFGBCHIDA
第六章樹(shù)_________________________________
I
2.森林的遍歷.—
i按照森林和樹(shù)的相互遞歸的定義,可以得到森林的兩種遍歷方法。
(1)森林的前序遍歷
森林的前序遍歷即依次按前序次序遍歷森林中的每一棵樹(shù),其形式化
的遞歸定義為:若森林非空,則先訪問(wèn)森林中第一棵樹(shù)的根結(jié)點(diǎn),然后前
序遍歷第一棵子樹(shù)中根結(jié)點(diǎn)的子樹(shù)森林,再前序遍歷除第一棵樹(shù)之外剩余
的樹(shù)構(gòu)成的森林。
(2)森林的后序遍歷
后序遍歷即依次按后序次序遍歷森林中的每一棵樹(shù),其形式化遞歸定
義為:若森林非空,則先后序遍歷森林中第一棵樹(shù)的根結(jié)點(diǎn)的子樹(shù)森林,
然后訪問(wèn)第一棵樹(shù)的根結(jié)點(diǎn),再后序遍歷除第一棵樹(shù)之外剩余的樹(shù)構(gòu)成的
森林O
何如,對(duì)圖6.21中的森林進(jìn)行前序和后序遍歷,其結(jié)果為:
前序遍歷序列:ABCDEFGHIK
后序遍歷序列:BCDAFEHKIG
第六章樹(shù)
.6.6哈夫曼樹(shù)
哈夫曼(Huffman)樹(shù)又稱最優(yōu)二叉樹(shù),是一類帶權(quán)路徑長(zhǎng)度最短
的二叉樹(shù),有著廣泛的應(yīng)用。本節(jié)先討論哈夫曼樹(shù)(最優(yōu)二叉樹(shù))的概
念,然后討論它的應(yīng)用及其算法實(shí)現(xiàn)。
6.6.1基本術(shù)語(yǔ)
1.路徑和路徑長(zhǎng)度
樹(shù)中兩個(gè)結(jié)點(diǎn)之間的路徑,是指從樹(shù)中一個(gè)結(jié)點(diǎn)到達(dá)另一個(gè)結(jié)點(diǎn)之
間的分支。
將路徑中所經(jīng)過(guò)的分支數(shù)稱為這兩個(gè)結(jié)點(diǎn)之間的路徑長(zhǎng)度,它等于路
徑上的結(jié)點(diǎn)數(shù)減1,即等于路徑上分支的數(shù)目j-1。
將從樹(shù)根到每一個(gè)結(jié)點(diǎn)的路徑長(zhǎng)度之和定義為樹(shù)的路徑長(zhǎng)度。
第六章樹(shù)
2.結(jié)點(diǎn)的權(quán)和帶權(quán)路徑長(zhǎng)度
.在許多實(shí)際應(yīng)用中,常為樹(shù)中的結(jié)點(diǎn)賦于一個(gè)有某種意義祥照,
稱之為該結(jié)點(diǎn)的權(quán)。
將結(jié)點(diǎn)的帶權(quán)路徑長(zhǎng)度規(guī)定為從樹(shù)根結(jié)點(diǎn)到該結(jié)點(diǎn)之間的路徑長(zhǎng)度
與該結(jié)點(diǎn)權(quán)值的乘積。
3.樹(shù)的帶權(quán)路徑長(zhǎng)度
樹(shù)的帶權(quán)路徑長(zhǎng)度(WeightedPathLength)為樹(shù)中所有葉子結(jié)點(diǎn)
的帶權(quán)路徑長(zhǎng)度之和,通常記為:
n
W尸L=>wz.Zz-
£=1
其中,n表示帶權(quán)葉子結(jié)點(diǎn)的數(shù)目,Wj表示葉子用的權(quán)值,L表示
由樹(shù)的根到葉子結(jié)點(diǎn)ki之間的路徑長(zhǎng)度。
例如,圖6.22計(jì)算每一棵二叉樹(shù)的帶權(quán)路徑長(zhǎng)度WPL分別為:
第六章樹(shù)
圖6.22具有不同帶權(quán)路徑長(zhǎng)度的二叉樹(shù)
(a)WPL=7X3+1X3+2X2+5X1=33
(b)WPL=1X3+2X3+5X2+7X1=26
(c)WPL=1X2+7X3+2X4+5X4=51
第六章樹(shù)
4,哈夫曼樹(shù)
哈夫曼樹(shù)(HuffmanTree)是指由n個(gè)帶權(quán)葉子結(jié)點(diǎn)構(gòu)成的所有
二叉樹(shù)中帶權(quán)路徑長(zhǎng)度WPL最小的二叉樹(shù),又稱最優(yōu)二叉樹(shù)。相應(yīng)的,
其構(gòu)造算法稱為哈夫曼算法。
對(duì)于具有n個(gè)其權(quán)值分別為Wjw2,Wn的帶權(quán)葉子結(jié)點(diǎn)的二
叉樹(shù)來(lái)說(shuō),其形態(tài)可以有許多種,其中能被稱為哈夫曼樹(shù)的二叉樹(shù)是
不唯一的,但其最小的WPL是確定的,而且在葉子數(shù)目及權(quán)值相同的
二叉樹(shù)中,完全二叉樹(shù)不一定是最優(yōu)二叉樹(shù)。一般情況下,在哈夫曼
樹(shù)中,權(quán)值越大的葉子結(jié)點(diǎn)離根結(jié)點(diǎn)越近。
第六章樹(shù)
6.6.2哈夫曼算法
(1)根據(jù)給定的n個(gè)權(quán)值{wLw2,…,wn)構(gòu)成n棵二叉樹(shù)的森林
F={T1,T2,…,Tn},其中每棵二叉樹(shù)Ti(IWiWn)都只有一個(gè)權(quán)值為wi的
根結(jié)點(diǎn),其左、右子樹(shù)均為空;
(2)在森林F中選出兩棵根結(jié)點(diǎn)的權(quán)值最小的二叉樹(shù)作為一棵新的二
叉樹(shù)的左、右子樹(shù),且置新的二叉樹(shù)的根結(jié)點(diǎn)的權(quán)值為其左、右子樹(shù)上根
結(jié)點(diǎn)的僅值之和;
八(3)從森林F中刪除這兩棵二叉樹(shù),同時(shí)將新得到的二叉樹(shù)加入到F中;
(4)重復(fù)(2)和(3)步驟,直到F中只含一棵二叉樹(shù)為止,此二叉
樹(shù)便是所構(gòu)造的哈夫曼樹(shù)。
例如,上例中由4個(gè)帶權(quán)為7,1,2,5的葉子結(jié)點(diǎn)A,B,C,D,根據(jù)
哈夫曼算法構(gòu)造其對(duì)應(yīng)哈夫曼樹(shù)的過(guò)程如圖6.23所示。
第六章樹(shù)
15
71257
(a)(b)(c)(d)
圖6.23哈夫曼樹(shù)的構(gòu)造過(guò)程
第六章樹(shù)
6.6.3哈夫曼編碼
哈夫曼算法的應(yīng)用很廣泛,本節(jié)以遠(yuǎn)距離電報(bào)通訊中的編碼為例來(lái)
說(shuō)明它的應(yīng)用。
(1)編碼和譯碼
在電報(bào)通訊中,需要將欲傳送電文中的字符轉(zhuǎn)換成由二進(jìn)制的0、1
序列,然后進(jìn)行傳送,并在接收端將收到的二進(jìn)制串轉(zhuǎn)化為對(duì)應(yīng)的字符
序列。一般的,編碼的方法有等長(zhǎng)編碼和不等長(zhǎng)編碼等。等長(zhǎng)編碼即為
每個(gè)字符編制的二進(jìn)制碼的碼長(zhǎng)相同。
(2)等長(zhǎng)編碼
例如,電文為“ABACCDA”,由于其中出現(xiàn)的字符只有四種,所以
只需兩個(gè)字符的二進(jìn)制串便可分辨。若將其等長(zhǎng)編碼設(shè)計(jì)為:A:00,B:
01,C:10,D:11,則上述七個(gè)字符的電文便為“00010010101100”,
總長(zhǎng)度14位,接收端接收并進(jìn)行譯碼時(shí),可按二位一分割譯碼即可得相
應(yīng)的電文。顯然,利用等長(zhǎng)編碼方法進(jìn)行編碼,譯碼方便,但編碼所得
到的碼串過(guò)于冗長(zhǎng)。
第六章樹(shù)
(3)不等長(zhǎng)編碼
如上例中,A、C字符出現(xiàn)的次數(shù)較多,這樣可以設(shè)計(jì)字符A、B、C、
D的編碼分別為0、00、1和01,則上述共7個(gè)字符的電文可編碼為總長(zhǎng)度
為9的二進(jìn)制字符串“000011010”。顯然,其編碼總長(zhǎng)度大幅度減少,但
在譯碼時(shí)會(huì)帶來(lái)麻煩。例如,在接收端接收到的二進(jìn)制串中前四個(gè)字符
的子串“0000”就可有多種譯法,可以是“AAAA”,或是“ABA”,也可
以是“BB”等,顯然是不合適的,原因在于以上編碼不是前綴編碼因而
在譯碼時(shí)會(huì)產(chǎn)生多義性。
(4)前綴編碼
若利用不等長(zhǎng)編碼,要求字符集中任一個(gè)字符的編碼都不能是其它
字符編碼的前綴,這種編碼稱做前綴編碼(PrefixCode)??梢岳枚鏄?shù)
來(lái)設(shè)計(jì)二進(jìn)制的前綴編碼。用葉子結(jié)點(diǎn)表示要編碼的字符,并約定左分
支為‘0"右分支為'「,然后就可以用從根到葉子結(jié)點(diǎn)的路徑上分支字
符組成的串作為該字符的編碼,這樣得到的編碼必為二進(jìn)制前綴編碼。
第六章樹(shù)
01
0
0
?
圖6.24前綴編碼示例
第六章樹(shù)
(5)哈夫曼編碼.、一
S假設(shè)每種字符在電文中出現(xiàn)的次數(shù)為巧,其編碼長(zhǎng)度為L(zhǎng),電文中有n
種字符,則電文總長(zhǎng)度應(yīng)為WJ+W2I2+…+wj=0對(duì)應(yīng)到二叉樹(shù)上,
n可以看作是二叉樹(shù)中葉子結(jié)點(diǎn)的個(gè)數(shù),Wj可以著作是葉子結(jié)點(diǎn)的權(quán)值,I
恰為從根結(jié)點(diǎn)到葉子結(jié)點(diǎn)Kj的路徑長(zhǎng)度,顯然,設(shè)計(jì)電文總長(zhǎng)度最短的二
進(jìn)制前綴編碼即是構(gòu)造以字符出現(xiàn)頻率作為權(quán)值的具有n個(gè)葉子結(jié)點(diǎn)的哈
夫曼樹(shù),由此所得到的二進(jìn)制前綴編碼稱為哈夫曼編碼(Huffman
Code)o
例,假設(shè)電文中出現(xiàn)5個(gè)字符A、B、C、D、E,已知它們?cè)陔娢闹?/p>
出現(xiàn)的頻率是9、3、7、6、1,利用{9,3,7,6,1}為權(quán)值構(gòu)造的哈夫曼
樹(shù)如圖6.25所示,其編碼分別為:A:00,B:100,C:01,D:11,E:
101o
哈夫曼樹(shù)也可以用來(lái)譯碼,譯碼時(shí)從根結(jié)點(diǎn)出發(fā),按二進(jìn)制位串中的
0和1確定是進(jìn)入左分支還是進(jìn)入到右分支,當(dāng)?shù)竭_(dá)葉子結(jié)點(diǎn)時(shí)便可譯出該
葉子對(duì)應(yīng)的字符,若電文未完,則回到根結(jié)點(diǎn)繼續(xù)進(jìn)行譯碼。
第六章樹(shù)
26
9376196
@@?@?
(a)
圖6.25哈夫曼樹(shù)及哈夫曼編碼
第六章樹(shù)
6.6.4哈夫曼算法的實(shí)現(xiàn)■
1.哈夫曼樹(shù)的構(gòu)造算法
用一個(gè)大小為2n?l的一維數(shù)組構(gòu)成靜態(tài)鏈表來(lái)存放哈夫曼樹(shù)中的結(jié)點(diǎn)。
如圖6.26所示的靜態(tài)鏈表。其中data為數(shù)據(jù)域,Ichild為左孩子指針域,
rchild為右孩子指針域,parent為雙親指針域,’0,表示空指針。
dataIchiIdrchilddataIchildparentrchild
A231A203
B452B415
C673C617
D004D020
E005E020
F006F030
G007G030
(a)二叉樹(shù)(b)二叉靜態(tài)鏈表(c)三叉靜態(tài)鏈表
第六章樹(shù)
結(jié)點(diǎn)結(jié)構(gòu)描述:
typedefstruct
{floatweight;/*數(shù)據(jù)域用于存放權(quán)值*/
intIchild,pa
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年陜煤電力上高有限公司招聘筆試參考題庫(kù)含答案解析
- 旅行社租賃合同附旅游線路清單
- 地下倉(cāng)庫(kù)建設(shè)鉆井施工合同
- 滑坡防治土方施工合同
- 二零二五年度白酒企業(yè)線上線下融合銷售合同2篇
- 體育俱樂(lè)部外籍教練聘用合同
- 高科技貿(mào)易公司聘用合同
- 二零二五年度水利工程款支付與水資源合理利用合同范本3篇
- 企業(yè)培訓(xùn)中心會(huì)議室建設(shè)合同
- 棋牌俱樂(lè)部章程草案范本
- 電纜及電纜橋架安裝施工方案
- 跨部門(mén)溝通與協(xié)調(diào)課件
- 醫(yī)生進(jìn)修報(bào)告ppt通用模板
- 2022年版《義務(wù)教育信息科技技術(shù)新課程標(biāo)準(zhǔn)》試題與答案
- 汽車OTS工程樣件認(rèn)可流程課件
- 明細(xì)賬(三欄式)模板
- 三年級(jí)數(shù)學(xué)思維訓(xùn)練【奧數(shù)舉一反三】附部分答案解析
- 2023年數(shù)學(xué)競(jìng)賽AMC8真題A卷(含答案)
- 審計(jì)控制活動(dòng)方案
- 單位洗車房管理制度
- 2023年醫(yī)療軟件實(shí)施工程師年度總結(jié)及下年規(guī)劃
評(píng)論
0/150
提交評(píng)論