數(shù)據(jù)結(jié)構(gòu)第6章_樹PPT課件_第1頁
數(shù)據(jù)結(jié)構(gòu)第6章_樹PPT課件_第2頁
數(shù)據(jù)結(jié)構(gòu)第6章_樹PPT課件_第3頁
數(shù)據(jù)結(jié)構(gòu)第6章_樹PPT課件_第4頁
數(shù)據(jù)結(jié)構(gòu)第6章_樹PPT課件_第5頁
已閱讀5頁,還剩80頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、2021-11-1316.1 6.1 樹的概念 樹的定義(遞歸定義):樹(Tree)是n(n0)個結(jié)點的有限集合T,滿足兩個條件:(1)有且僅有一個特定的稱為根(Root)的結(jié)點,它沒有前趨;(2)其余的結(jié)點可分成m個互不相交的有限集合T1,T2,Tm,其中每個集合又是一棵樹,并稱為根的子樹。當n=0時的空集合定義為空樹。第1頁/共85頁2021-11-132使用圓圈表示結(jié)點,連線表示結(jié)點之間的關(guān)系,結(jié)點的名字可寫在圓圈內(nèi)或圓圈旁。學校一系二系十系一室八室一室七室n樹的直觀表示法第2頁/共85頁2021-11-133n樹的基本術(shù)語l 結(jié)點:指樹中的一個元素,包含數(shù)據(jù)項及若干指向其子樹的分支。l

2、 結(jié)點的度:指結(jié)點擁有的子樹個數(shù)。l 樹的度:指樹中結(jié)點的度的最大值。第3頁/共85頁2021-11-134l 葉子:指度為零的結(jié)點,又稱為終端結(jié)點。l 孩子:一個結(jié)點的子樹的根稱為該結(jié)點的孩子。l 雙親:一個結(jié)點的直接上層結(jié)點稱為該結(jié)點的雙親。l 兄弟:同一雙親的孩子互稱為兄弟。l 結(jié)點的層次:從根結(jié)點開始,根結(jié)點為第一層,根的孩子為第二層,根的孩子的孩子為第三層,依次類推。l 樹的深度:樹中結(jié)點的最大層次數(shù)。l 堂兄弟:雙親在同一層上的結(jié)點互稱為堂兄弟。第4頁/共85頁2021-11-135l 路徑:若存在一個結(jié)點序列k1,k2,kj, 可使k1到達kj, 則稱這個結(jié)點序列是k1到達kj的

3、一條路徑。l 子孫和祖先:若存在k1到kj的一條路徑k1,k2,kj,則k1,kj-1為kj的祖先,而k2,kj為k1的子孫。l 森林:m(m0)棵互不相交的樹的集合構(gòu)成森林。l 有序樹和無序樹:若將樹中每個結(jié)點的各個子樹都看成是從左到右有次序的(即不能互換),則稱該樹為有序樹,否則為無序樹。第5頁/共85頁2021-11-136順序存儲順序存儲時,首先必須對樹形結(jié)構(gòu)的結(jié)點進行某種方式的線性化,使之成為一個線性序列,然后存儲。鏈式存儲鏈式存儲時,使用多指針域的結(jié)點形式,每一個指針域指向一棵子樹的根結(jié)點。由于樹的分支數(shù)不固定,很難給出一種固定的存由于樹的分支數(shù)不固定,很難給出一種固定的存儲結(jié)構(gòu),

4、通常采用二叉樹的形式存儲樹。儲結(jié)構(gòu),通常采用二叉樹的形式存儲樹。樹的存儲結(jié)構(gòu)第6頁/共85頁2021-11-1376.2 6.2 二叉樹 定義(二叉樹的遞歸定義):二叉樹是n(n0)個結(jié)點的有限集,它或為空樹(n=0),或由一個根結(jié)點及兩棵互不相交的、分別稱作這個根的左子樹和右子樹的二叉樹構(gòu)成。 二叉樹的五種基本形態(tài): 二叉樹與度為2的樹的區(qū)別:二叉樹的子樹有左右之分,而樹的子樹不分左右;第7頁/共85頁2021-11-138u滿二叉樹和完全二叉樹l 一棵深度為k且有2k-1個結(jié)點的二叉樹稱為滿二叉樹。滿二叉樹的特點是每一層的結(jié)點數(shù)都達到該層可具有的最大結(jié)點數(shù)。l 如果一個深度為k的二叉樹,它

5、的結(jié)點按照從根結(jié)點開始,自上而下,從左至右進行連續(xù)編號后,得到的順序與滿二叉樹相應結(jié)點編號順序一致,則稱這個二叉樹為完全二叉樹。完全二叉樹的1k-1層上共有2k-1-1個結(jié)點,第k層的結(jié)點集中在左邊。l 滿二叉樹一定是完全二叉樹,而完全二叉樹不一定是滿二叉樹。 1 3 7 5 6 4 2 k=3 的滿二叉樹 1 3 5 6 4 2 完全二叉樹 1 3 6 5 4 2 非完全二叉樹 第8頁/共85頁2021-11-139二叉樹的性質(zhì)-1 性質(zhì)1:在二叉樹的第i層上至多有2i-1個結(jié)點(i1)。 證明:可用數(shù)學歸納法予以證明。當i=1時,有2i-1=20=1,同時第一層上只有一個根結(jié)點,故命題成立

6、。設當i=k時成立,即第k層上至多有2k-1個結(jié)點。當i=k+1時,由于二叉樹的每個結(jié)點至多有兩個孩子,所以第k+1層上至多有22k-1=2k個結(jié)點,故命題成立。第9頁/共85頁2021-11-1310二叉樹的性質(zhì)-2 性質(zhì)2:深度為k的二叉樹至多有2k-1個結(jié)點(k1)。 證明:性質(zhì)1給出了二叉樹每一層中含有的最大結(jié)點數(shù),深度為k的二叉樹的結(jié)點總數(shù)至多為故命題成立。k1ik1- i1-22第10頁/共85頁2021-11-1311二叉樹的性質(zhì)-3 性質(zhì)3:對任何一棵二叉樹,如果其終端結(jié)點數(shù)為n0,度為2的結(jié)點數(shù)為n2,則n0=n2+1。 證明:設度為1的結(jié)點數(shù)為n1,則一棵二叉樹的結(jié)點總數(shù)為

7、: n=n0+n1+n2 因為除根結(jié)點外,其余結(jié)點都有一個進入的分支(邊),設B為分支總數(shù),則n=B+1。又考慮到分支是由度為1和2的結(jié)點發(fā)出的,故有 B=2n2+n1,即 n=2n2+n1+1 比較兩式可得n0=n2+1,證畢。第11頁/共85頁2021-11-1312二叉樹的性質(zhì)-4 性質(zhì)4:具有n個結(jié)點的完全二叉樹的深度為log2n+1或log2(n+1)。 (其中x表示不大于x的最大整數(shù),x表示不小于x的最小整數(shù)。) 證明:設完全二叉樹的深度為k,則有 2k-1 - 1 n 2k 1 (1) (1)式變形為 2k-1 n+1 2k,兩邊取對數(shù) k-1log2(n1) k 取整得 klo

8、g2(n+1) 2k-1 n 2k (第k層至少有一個結(jié)點) (2) 兩邊取對數(shù) k-1 log2n 1, 則 i 的雙親為i /2若2*i n, 則 i 的左孩子為2*i,否則無左孩子若2*i+1 n, 則 i 的右孩子為2*i+1,否則無右孩子若i為偶數(shù), 且i != n, 則其右兄弟為i+1若i為奇數(shù), 且i != 1, 則其左兄弟為i-1結(jié)點i 所在層次為 log2i +1第13頁/共85頁2021-11-13146.3 6.3 二叉樹的存儲結(jié)構(gòu)6.3.1 順序存儲結(jié)構(gòu) 完全二叉樹 根據(jù)二叉樹性質(zhì)5,在一棵完全二叉樹中,按照從根結(jié)點起,自上而下,從左至右的方式對結(jié)點進行順序編號,便可得

9、到一個反映結(jié)點之間關(guān)系的線性序列。 下圖的完全二叉樹的順序存儲結(jié)構(gòu)如下表: 左左圖圖的的完完全全二二叉叉樹樹的的順順序序存存儲儲 數(shù)組 下標 0 1 2 3 4 5 6 7 8 9 10 結(jié)點值 A B C D E F G H I J 1 5 4 2 9 8 10 A D B J I H E 3 7 6 C G F 完完全全二二叉叉樹樹的的結(jié)結(jié)點點編編號號 第14頁/共85頁2021-11-1315一般二叉樹將二叉樹映射為完全二叉樹(通過虛結(jié)點)用完全二叉樹的方式存儲。根據(jù)性質(zhì)2,采用順序存儲結(jié)構(gòu)存儲一棵深度為k的完全二叉樹或一般二叉樹,向量的長度是2k-1。第15頁/共85頁2021-11-

10、1316由于一般二叉樹必須仿照完全二叉樹那樣存儲,可能會浪費很多存儲空間,單支樹就是一個極端情況。存儲上述單支二叉樹,所需的向量長度為25-1=31第16頁/共85頁2021-11-13176.3.2 鏈式存儲結(jié)構(gòu)二叉樹的鏈式存儲結(jié)構(gòu)每個結(jié)點含有數(shù)據(jù)域和兩個指針域,左、右指針域分別用來指向左孩子和右孩子。二叉樹的鏈式存儲結(jié)構(gòu)也稱為二叉鏈表。二叉鏈表結(jié)點的C語言邏輯描述為:typedef int datatype;typedef struct node datatype data; struct node *lchild,*rchild;bitree;bitree *root;注:其中root是

11、指向根結(jié)點的指針,當二叉樹為空時,則root=NULL。若結(jié)點的某個孩子不存在時,則相應的指針域為空。第17頁/共85頁2021-11-1318三叉鏈表為了能夠?qū)ふ译p親結(jié)點,在結(jié)點中增加一個指向雙親結(jié)點的指針域parent。 A D B C (a) 二叉樹 A ? ? B ? C ? D A ? B ? C ? D ? (b)二叉鏈表 (c)三叉鏈表 ? ? ? 第18頁/共85頁2021-11-13196.3.3 二叉樹建立(二叉鏈表的建立)第19頁/共85頁2021-11-13206.3.3 6.3.3 二叉樹建立(二叉鏈表的建立)u二叉樹的建立 指在內(nèi)存中如何建立二叉樹的存儲結(jié)構(gòu)。u基本

12、思想 對順序存儲結(jié)構(gòu)而言,只需將二叉樹各個結(jié)點的值按原有的邏輯關(guān)系送入相應的向量單元中。對鏈式存儲結(jié)構(gòu)而言,其建立算法有多種,它們依賴于按照何種形式來輸入二叉樹的邏輯結(jié)構(gòu)信息。常用的算法是按照完全二叉樹的層次順序,依次輸入結(jié)點信息來建立二叉鏈表。對于一般二叉樹,則必須通過先添加若干個虛結(jié)點使其成為完全二叉樹。第20頁/共85頁2021-11-1321u 基本步驟問題:如何將新結(jié)點正確地鏈接到它的雙親結(jié)點上?第21頁/共85頁2021-11-1322 算法具體實現(xiàn)依據(jù)先建立的結(jié)點,其孩子結(jié)點也一定先建立的特點先建立的結(jié)點,其孩子結(jié)點也一定先建立的特點,所以可以第22頁/共85頁2021-11-1

13、323二叉樹的建立算法bitree *CREATREE( ) /* 建立二叉樹函數(shù),函數(shù)返回指向根結(jié)點的指針 */char ch; /* 結(jié)點信息變量 */ bitree *Q maxsize; /* 設置指針類型數(shù)組來構(gòu)成隊列 * intfront, rear; /* 隊頭和隊尾指針變量 */ bitree *root, *s; /* 根結(jié)點指針和中間指針變量 */ root=NULL; /* 二叉樹置空 */ front=1; rear=0; /* 設置隊列指針變量初值 */*以上為初始化*/第23頁/共85頁2021-11-1324while(ch=getchar()!=#) /* 輸入

14、一個字符,當不是結(jié)束符時執(zhí)行以下操作 */ s=NULL; if(ch!=) /* 表示虛結(jié)點,當不是虛結(jié)點則建立新結(jié)點 */ s=malloc(sizeof (bitree); sdata=ch; slchild=NULL; srchild=NULL; rear+; /* 隊尾指針增1,指向新結(jié)點地址應存放的單元 */ Qrear=s; /* 將新結(jié)點地址入隊或虛結(jié)點指針NULL入隊 */ if (rear= =1) root=s; /* 輸入的第一個結(jié)點作為根結(jié)點 */ else if (s & Qfront) /* 孩子和雙親結(jié)點都不是虛結(jié)點 */ if (rear % 2= =

15、0) Qfrontlchild=s;/*rear為偶數(shù),新結(jié)點是左孩子*/ else Qfrontrchild=s; /* rear為奇數(shù)且不等于1,新結(jié)點是右孩子 */ if (rear % 2= =1) front+; /* 結(jié)點* Qfront的兩個孩子處理完畢,出隊列 */ return root; /* 返回根指針 */ /* CREATREE */第24頁/共85頁2021-11-13256.4 6.4 二叉樹的遍歷 所謂樹的遍歷,就是按某種次序訪問樹中的結(jié)點,要求每個結(jié)點訪問一次且僅訪問一次。 遍歷的結(jié)果:產(chǎn)生一個關(guān)于結(jié)點的線性序列。6.4.1 深度優(yōu)先遞歸遍歷 訪問根結(jié)點記作

16、D 遍歷根的左子樹記作 L 遍歷根的右子樹記作 R 則可能的遍歷次序有: 先序 DLR 逆先序 DRL 中序 LDR 逆中序 RDL 后序 LRD 逆后序 RLD第25頁/共85頁2021-11-13261. 先序遍歷DLR先序遍歷算法的遍歷過程 遍歷結(jié)果: abdefc第26頁/共85頁2021-11-13272. 中序遍歷LDR中序遍歷算法的遍歷過程點 */ inorder (p-rchild); /* 中序遍歷右子樹 */ 遍歷結(jié)果:dbefac第27頁/共85頁2021-11-13283. 后序遍歷LRD后序遍歷算法的遍歷過程遍歷結(jié)果:dfebca第28頁/共85頁2021-11-13

17、296.4.2 二叉樹的廣度優(yōu)先遍歷(按層次遍歷二叉樹)從根開始逐層訪問。先遍歷二叉樹的第一層結(jié)點,然后遍歷第二層結(jié)點,最后遍歷最下層的結(jié)點。而對每一層的遍歷是按從左至右的方式進行。在上層中先被訪問的結(jié)點,它的下層孩子也必然先被訪問,因此在這種遍歷算法的實現(xiàn)時,需要使用一個隊列。在遍歷進行之前先把二叉樹的根結(jié)點的存儲地址入隊,然后依次從隊列中出隊結(jié)點的存儲地址,每出隊一個結(jié)點的存儲地址則對該結(jié)點進行訪問,然后依次將該結(jié)點的左孩子和右孩子的存儲地址入隊,如此反復,直到隊空為止。廣度優(yōu)先遍歷算法第29頁/共85頁2021-11-1330Bitree *Qmaxsize;void layer(BiT

18、ree *p) BiTree *s; if (p!=NULL) rear=1; front=0; Qrear=p; while (frontdata); if (s-lchild!=NULL) /左子樹非空 rear+; Qrear=s-lchild; /左子樹根結(jié)點入隊 二叉樹的廣度優(yōu)先遍歷實例第30頁/共85頁2021-11-1331 if (s-rchild !=NULL) /右子樹非空 rear+; Qrear=s-lchild; /右子樹根結(jié)點入隊 第31頁/共85頁2021-11-1332ABCDEFG第32頁/共85頁2021-11-13336.4.3 深度優(yōu)先的非遞歸算法 分析

19、:二叉樹的深度優(yōu)先遍歷算法是以遞歸形式給出的,運行效率低,可讀性不強。因遞歸調(diào)用過程要用到棧來保存每次調(diào)用的參數(shù),所以,我們可以用棧來實現(xiàn)二叉樹的深度優(yōu)先遍歷,將遞歸算法轉(zhuǎn)化為非遞歸算法。 以中序遍歷為例,在遍歷左子樹之前,先把根結(jié)點入棧,當左子樹遍歷結(jié)束后,從棧中彈出并訪問根結(jié)點,再遍歷右子樹。算法執(zhí)行過程第33頁/共85頁2021-11-1334void inorder(BiTree *T) SqStack *S; BiTree *P=T;/P為工作指針I(yè)nitStack(S); /*順序棧初始化*/while( P!=NULL | !Empty(S) if (P!=NULL) Push(

20、S,P); /*根結(jié)點入棧*/ P=P-lchild; /* 遍歷左子樹*/ else Pop(S,P); /*左子樹遍歷結(jié)束,出棧 */ printf(%c,P-data); P=P-rchild; /*遍歷右子樹*/ 第34頁/共85頁2021-11-1335&a&b&d&c棧的變化情況輸出序列為:dbac第35頁/共85頁2021-11-13366.4.4 從遍歷序列恢復二叉樹可以由DLR和LDR的遍歷序列可以唯一地確定一棵二叉樹,或者由LRD和LDR的遍歷序列可以唯一地確定一棵二叉樹。通過DLR或者LRD的遍歷序列確定二叉樹或子樹的根結(jié)點;通過LDR確定

21、左、右子樹的序列。第36頁/共85頁2021-11-1337例: 由先序序列 ABHFDECKG 和中序序列 HBDFAEKCG 恢復二叉樹的過程。第37頁/共85頁2021-11-13386.4.5 遍歷算法的應用1.統(tǒng)計二叉樹的葉子結(jié)點數(shù)int count =0; int countleaf(bitree *p) if ( p != NULL ) count = countleaf( plchild ); /* 對左子樹上的葉子結(jié)點計數(shù)*/ if ( (plchild= =NULL)&(prchild= =NULL) count=count+1;count = countleaf(

22、prchild); /* 對右子樹上的葉子結(jié)點計數(shù)*/ return count; 請考慮如何統(tǒng)計度為1的結(jié)點數(shù),度為2的結(jié)點數(shù)。第38頁/共85頁2021-11-13392.利用二叉樹先序遍歷計算二叉樹的深度int l=h=0; int treedepth(bitree * p, int l )if ( p!= NULL) l+; if ( lh ) h=l; h=treedepth( plchild, l ); / 計算左子樹的深度 h=treedepth( prchild, l ); /計算右子樹的深度 return h; 第39頁/共85頁2021-11-13403.求二叉樹結(jié)點個數(shù)i

23、nt Size(BiTree *T) if (T=NULL) return (0); else return (1 + Size (T-lchild ) + Size ( T-rchild); /二叉樹的結(jié)點個數(shù)是根結(jié)點、左右子樹結(jié)點個數(shù)之和4.交換左右子樹void Exchange(BiTree *T)BiTree *S;if (T!=NULL) S=T-lchild; T-lchild=T-rchild;T-rchild=S;Exchange(T-lchild);Exchange(T-rchild);第40頁/共85頁2021-11-13415.利用先序遍歷方法,以嵌套括號的形式輸出二叉樹

24、的層次結(jié)構(gòu)void OutBT(BiTree *p) if (p!=NULL) printf(“%c”,p-data); if(p-lchild!=NULL|p-rchild!=NULL) /有左子樹或右子樹 printf( “(” ); OutBT(p-lchild); /遍歷左子樹 if(p-rchild!=NULL) printf( “,” ); /有右子樹輸出逗號 OutBT(p-rchild); /遍歷右子樹 printf( “)” ); 輸出的結(jié)果第41頁/共85頁2021-11-1342輸出的結(jié)果:A(B(D(,G),E),C(F)ABCDEFG第42頁/共85頁2021-11-

25、13436.5 6.5 樹和森林任何一棵樹(T)都可以轉(zhuǎn)換為一棵二叉樹(T),同樣一棵二叉樹也可轉(zhuǎn)換成一棵樹,而且這種轉(zhuǎn)換是具有惟一性的。1.樹轉(zhuǎn)為二叉樹 在兄弟之間增加一條連線; 對每個結(jié)點,除了保留與其左孩子的連線外,除去與其他孩子之間的連線。 以樹的根結(jié)點為軸心,將整個樹順時針旋轉(zhuǎn)45。2.二叉樹轉(zhuǎn)為樹 若結(jié)點X是雙親Y的左孩子,則將X的右孩子,右孩子的右孩子,都與X的雙親結(jié)點Y用線相連; 去掉原有的雙親到右孩子的連線。第43頁/共85頁2021-11-1344 (c) A D I G H E B C F (d) A D I G H E B C F (a) T AFDGBECIH ( b

26、 ) T (c) (c) (c)第44頁/共85頁2021-11-13456.6 6.6 線索二叉樹遍歷二叉樹是將一個非線性結(jié)構(gòu)進行線性化的操作,使每個結(jié)點(除第一個和最后一個)在這些線性序列中有且僅有一個直接前趨和直接后繼。當以二叉鏈表作為存儲結(jié)構(gòu)時,如果希望能直接得到結(jié)點在任一序列(先序、中序或后序)中的前驅(qū)和后繼信息,而不需要每次對二叉樹進行遍歷,有必要引入線索二叉樹。線索是指向結(jié)點前趨和后繼的指針,若結(jié)點有左孩子,則lchild指示其左孩子,否則lchild中存儲該結(jié)點的前趨結(jié)點的指針;若結(jié)點有右孩子,則rchild指示其右孩子,否則rchild中存儲指向該結(jié)點的后繼結(jié)點的指針。按照不

27、同的遍歷序列,可以得到先序、中序和后序線索二叉樹。第45頁/共85頁2021-11-1346 有n個結(jié)點的二叉鏈表中必然存在n1個空的指針域,利用空的指針域來存放結(jié)點的前趨和后繼信息是可行的。線索二叉樹的結(jié)點結(jié)構(gòu)實質(zhì)上利用二叉鏈表中的空指針域作為線索。 二叉樹的線索化的實質(zhì)是將二叉鏈表中的空指針改為指向前趨或后繼的線索。因為前趨或后繼的信息只有在遍歷時才能得到,因此線索化的過程就是在遍歷過程中修改空指針的過程。第46頁/共85頁2021-11-1347中序線索二叉樹及線索鏈表中序遍歷序列:BDAEC第47頁/共85頁2021-11-13486.7 6.7 二叉樹的應用6.7.1 哈夫曼樹及應用

28、1.基本概念路徑長度 兩個結(jié)點之間的路徑長度是連接兩結(jié)點的路徑上的分支數(shù)。樹的路徑長度是各結(jié)點到根結(jié)點的路徑長度之和。(a)PL=0+1(a)PL=0+1* *2+22+2* *4+3=134+3=13(b)PL=0+1(b)PL=0+1* *2+22+2* *3+33+3* *2=142=14第48頁/共85頁2021-11-1349帶權(quán)路徑長度 樹的帶權(quán)路徑長度是樹的各葉子結(jié)點所帶的權(quán)值與該結(jié)點到根的路徑長度的乘積的和。 其中n為樹中葉子結(jié)點的數(shù)目,wi為葉子結(jié)點i的權(quán)值,li為葉子結(jié)點i到根結(jié)點之間的路徑長度。niiilwWPL1第49頁/共85頁2021-11-1350葉子結(jié)點的權(quán)值相

29、同,具有不同帶權(quán)路徑長度的二叉樹哈夫曼樹 帶權(quán)路徑長度最小的二叉樹稱為哈夫曼樹(最優(yōu)二叉樹)。在哈夫曼樹中,權(quán)值越大的結(jié)點離根越近。第50頁/共85頁2021-11-1351哈夫曼樹的不唯一性 權(quán)值為w1,w2, ,wn 的n個葉子結(jié)點形成的二叉樹,可以具有多種形態(tài),其中能被稱為哈夫曼樹的二叉樹并不是唯一的。如下圖。 b d c a 3 4 5 7 (a) (b) b a c d 3 4 5 7 不不同同形形態(tài)態(tài)的的哈哈夫夫曼曼樹樹 (a) WPL =3242527238;(b) WPL =334352738。第51頁/共85頁2021-11-1352完全二叉樹不一定是哈夫曼樹 在葉子數(shù)和權(quán)值

30、相同的二叉樹中,完全二叉樹不一定是哈夫曼樹(最優(yōu)二叉樹)。如下圖。 (a) (b) 5 a d c b 4 2 7 b d c a 2 4 5 7 完完全全二二叉叉樹樹與與哈哈夫夫曼曼樹樹 (a) WPL2242527236;(b) WPL2343527135。第52頁/共85頁2021-11-13532.哈夫曼樹的構(gòu)造哈夫曼樹的構(gòu)造 哈夫曼算法:哈夫曼算法:(1) 由給定的由給定的n個權(quán)值個權(quán)值w0, w1, w2, , wn-1,構(gòu)成具有,構(gòu)成具有n棵棵二叉樹的集合二叉樹的集合F = T0, T1, T2, , Tn-1,其中每一棵二叉,其中每一棵二叉樹樹Ti只有一個帶有權(quán)值只有一個帶有權(quán)

31、值wi的根結(jié)點,其左、右子樹均為的根結(jié)點,其左、右子樹均為空???。 (2) 重復以下步驟重復以下步驟, 直到直到F中僅剩下一棵樹為止:中僅剩下一棵樹為止:第53頁/共85頁2021-11-1354 又一權(quán)值集合0.1,0.02,0.1,0.08,0.1,0.3,0.4,試構(gòu)造一顆huffman樹第54頁/共85頁2021-11-1355第55頁/共85頁2021-11-13563. 哈夫曼樹的應用最佳判定算法例:編制一個將百分制轉(zhuǎn)換成五級制的程序,使比較次數(shù)最少。各分數(shù)段分布情況如下:百分制05960697079808990100五級制不及格(E)及格(D)中(C)良(B)優(yōu)(A)比例數(shù)0.0

32、50.150.40.30.1第56頁/共85頁2021-11-13571 10.40.40.60.60.30.30.30.30.150.150.150.150.050.050.10.1AEDBCs80s70s90s60EDCBAFTTFFTTF?第57頁/共85頁2021-11-1358哈夫曼編碼主要用途是實現(xiàn)數(shù)據(jù)壓縮。 設給出一段報文: abaccda 字符集合是 a, b, c, d ,各個字符出現(xiàn)的頻度(次數(shù))是 W 3, 1, 2, 1。 若給每個字符以等長編碼 a : 00 b : 01 c : 10 d : 11則總編碼為00010010101100長度為 ( 3+1+2+1 )

33、* 2 = 14 若按各個字符出現(xiàn)的概率不同而給予不等長編碼,可望減少總編碼長度。 因各字符出現(xiàn)的概率為 3/7, 1/7, 2/7, 1/7。第58頁/共85頁2021-11-1359第59頁/共85頁2021-11-1360構(gòu)造哈夫曼樹算法中的數(shù)據(jù)結(jié)構(gòu) 存儲結(jié)構(gòu)define n 葉子數(shù)目define m 2*n-1 /* 結(jié)點總數(shù) */ typedef char datatype; typedef struct float weight; datatype data; int lchild, rchild, parent; hufmtree;hufmtree treem; 采用順序存儲結(jié)構(gòu)

34、,每個結(jié)點為一個結(jié)構(gòu)體。第60頁/共85頁2021-11-1361構(gòu)造哈夫曼樹算法實現(xiàn) HUFFMAN(hufmtree tree )int i, j, p; char ch; float small1, small2, f; for( i=0; im; i+) /* 初始化 */ treei.parent=0; treei.lchild=0; treei.rchild=0; treei.weight=0.0; treei.data= 0; for( i=0; in; i+) /輸入n個結(jié)點的權(quán)值和結(jié)點值 scanf(“ %f ”, &f); treei.weight=f; scanf

35、(“ %c ”,&ch); treei.data=ch; 第61頁/共85頁2021-11-1362 for( i=n; im ;i+ ) / 進行n-1次合并,產(chǎn)生n-1個新結(jié)點 p1=p2=0; / 記錄權(quán)值最小、次最小的結(jié)點下標 small1=small2=Maxval; /Maxval是float類型的最大值 / 從下標0掃描到已生成的結(jié)點下標 for ( j=0; j=i-1; j+ ) if ( treej.parent= =0) if ( treej.weightsmall1 ) small2=small1; /改變最小權(quán),次最小權(quán)及對應位置 small1=treej.w

36、eight; p2=p1; p1=j; else if( treej.weightsmall2 ) /改變次小權(quán)及位置 small2=treej.weight; p2=j; treep1.parent=i; /給合并的兩個結(jié)點的雙親域賦值 treep2.parent=i; treei.lchild=p1;/ 給新生成的結(jié)點的左右孩子域賦值 treei.rchild=p2; treei.weight =treep1.weight+treep2.weight;/給新生成的結(jié)點的權(quán)值域賦值 /* HUFFMAN */第62頁/共85頁2021-11-1363構(gòu)造哈夫曼樹算法的基本思想:對m=2n-1

37、個結(jié)點初始化,將雙親域,左、右孩子域,權(quán)值,結(jié)點值置0;輸入n個葉子結(jié)點的權(quán)值和結(jié)點值;循環(huán)體執(zhí)行n-1次,進行n-1次合并,產(chǎn)生n-1個新結(jié)點: 在i個結(jié)點中找出兩個雙親域為0(即沒有被合并的結(jié)點)且權(quán)值最小的結(jié)點,p1指示權(quán)值最小的結(jié)點,p2指示權(quán)值次最小的結(jié)點; 將兩棵根結(jié)點權(quán)值最小的二叉樹進行合并: treep1.parent=i; /i為新結(jié)點,即新產(chǎn)生的雙親結(jié)點treep2.parent=i; treei.lchild=p1; /新產(chǎn)生的雙親結(jié)點指向左、右子樹的根結(jié)點 treei.rchild=p2; treei.weight = treep1.weight+treep2.weig

38、ht; /新結(jié)點的權(quán)值是左、右子樹根結(jié)點權(quán)值之和。第63頁/共85頁2021-11-1364哈夫曼編碼的數(shù)據(jù)結(jié)構(gòu)編碼數(shù)組結(jié)構(gòu)描述如下:typedef char datatype;typedef struct char bitsn; /編碼數(shù)組位串,其中n為葉子結(jié) 點數(shù)目 int start; /編碼在位串的起始位置 datatype data; /結(jié)點值 codetype;codetype coden; 一個字符的哈夫曼編碼在數(shù)組bits中從高位到低位順序存儲。第64頁/共85頁2021-11-1365哈夫曼編碼的算法的基本思想 從葉子到根逆向求哈夫曼編碼 從葉子treei出發(fā),利用雙親地址找

39、到雙親結(jié)點treep,再利用treep的lchild和rchild指針域判斷treei是treep的左孩子還是右孩子,然后決定分配代碼的 0 還是代碼 1 , 然后以treep為出發(fā)點繼續(xù)向上回溯,直到根結(jié)點為止。第65頁/共85頁2021-11-1366哈夫曼編碼算法實現(xiàn)void HUFFMANCODE(codetype code ,hufmtree tree )/code 存放求出的哈夫曼編碼的數(shù)組, tree已知的哈夫曼樹 int i, c, p; codetype cd; / 緩沖變量 for ( i=0; in; i+ ) /n為葉子結(jié)點數(shù)目 ,循環(huán)產(chǎn)生n個字符的哈夫曼編碼 cd.

40、start=n; /從葉子結(jié)點出發(fā)向上回溯 ,在bits中, 從高位開始存儲 c=i; /c指示第i個葉子結(jié)點 p=treec.parent; /p指示結(jié)點c的雙親結(jié)點 cd.data=treec.data; /對結(jié)點數(shù)據(jù)域賦值 第66頁/共85頁2021-11-1367 while( p!=0 ) /c指示到根結(jié)點時,p為0 cd.start - ; if( treep. lchild = = c) cd.bitscd.start= 0; else cd.bits cd.start=1; /若結(jié)點c是雙親結(jié)點p的左孩子,置0;否則就是右孩子,置1 c=p; /雙親結(jié)點p作為孩子結(jié)點,用c指示

41、 p=treec.parent; /p指示結(jié)點c的雙親結(jié)點 codei=cd; /一個字符的編碼存入codei /for_end / HUFFMANCODE第67頁/共85頁2021-11-1368哈夫曼編碼結(jié)果 對下圖所示的哈夫曼樹進行編碼,可得到下表所示的編碼表。code下標bitsstartdata0123003a11101b2102c31111d第68頁/共85頁2021-11-1369哈夫曼樹譯碼 定義:哈夫曼樹譯碼是指由給定的代碼求出代碼所表示的結(jié)點值。 譯碼的過程是:從根結(jié)點出發(fā),逐個讀入電文中的二進制代碼;若代碼為0則走向左孩子,否則走向右孩子;一旦到達葉子結(jié)點,便可譯出代碼所

42、對應的字符。然后又重新從根結(jié)點開始繼續(xù)譯碼,直到二進制電文結(jié)束。第69頁/共85頁2021-11-1370哈夫曼樹譯碼算法void HUFFMANDECODE(codetype code ,hufmtree tree )int i, c, p, b; int endflag=-1; /* 電文結(jié)束標志取-1 */ i=m-1; /* 從根結(jié)點開始向下搜索 */ scanf ( “%d”, &b); /* 讀入一個二進制代碼 */ while ( b != endflag) if( b= =0) i=treei.lchild; /* 走向左孩子 */ else i=treei.rchil

43、d; /* 走向右孩子 */ if ( treei.lchild= =0 ) /* treei是葉子結(jié)點 */ putchar( codei.data); i=m-1; /* 回到根結(jié)點 */ scanf(“%d”, &b); /* 讀入下一個二進制代碼 */ if (treei.lchild!=0)&(i!=m-1) ) /* 電文讀完尚未到葉子結(jié)點 */ printf( “n ERRORn”); /* 輸入電文有錯 */ /* HUFFMANDECODE */ 說明:treei.lchild為0,treei.rchild也必然為0,因為哈夫曼樹沒有度為1的結(jié)點,所以tree

44、i是葉子結(jié)點。第70頁/共85頁2021-11-13716.7.2 二叉排序樹二叉排序樹的概念: 二叉排序樹或者是一棵空樹,或者是具有下列性質(zhì)的二叉樹: 每個結(jié)點都有一個關(guān)鍵字(key),所有結(jié)點的關(guān)鍵字互不相同。 左子樹(若非空)上所有結(jié)點的關(guān)鍵字都小于根結(jié)點的關(guān)鍵字。 右子樹(若非空)上所有結(jié)點的關(guān)鍵字都大于根結(jié)點的關(guān)鍵字。 左子樹和右子樹也是二叉排序樹。第71頁/共85頁2021-11-1372幾個二叉排序樹的例子幾個二叉排序樹的例子第72頁/共85頁2021-11-1373二叉排序樹的數(shù)據(jù)結(jié)構(gòu) 二叉排序樹的二叉鏈表存儲結(jié)構(gòu)結(jié)點結(jié)構(gòu)描述如下:typedef int keytype;typ

45、edef struct keytype key; /關(guān)鍵字項 datatype other; / 其它數(shù)據(jù)項 struct node *lchild, *rchild; /左、右指針域 bstnode;第73頁/共85頁2021-11-1374二叉排序樹的構(gòu)造 構(gòu)造一棵二叉排序樹,就是從空的二叉排序樹開始,逐個結(jié)點插入到二叉排序樹中。 對于一組數(shù)據(jù)元素 R1, R2, , Rn , 可按以下方法來構(gòu)造二叉排序樹:說明:每次插入的新結(jié)點都是當前二叉樹的葉子結(jié)點 給定的關(guān)鍵字序列不同,二叉排序樹的形態(tài)則不同 二叉排序樹中不存在兩個結(jié)點的關(guān)鍵字相同的結(jié)點第74頁/共85頁2021-11-1375例:給定關(guān)鍵字序列10、18、3

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論