




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、第六章樹和二叉樹教學(xué)目的和要求1、熟練掌握二叉樹的結(jié)構(gòu)特點,了解相應(yīng)的證明。2、熟悉二叉樹的各種存儲結(jié)構(gòu)的特點及適用范圍。3、掌握二叉樹遍歷的遞歸與非遞歸算法。4、掌握二叉線索樹的相關(guān)算法。5、熟悉樹的各種存儲結(jié)構(gòu)及特點,掌握樹和森林與二叉樹的方法。6、了解最優(yōu)樹的特性,掌握最優(yōu)樹和哈夫曼編碼的方法。 1數(shù)據(jù)的邏輯結(jié)構(gòu) 2、數(shù)據(jù)的存儲結(jié)構(gòu) 3、數(shù)據(jù)的運(yùn)算:檢索、排序、插入、刪除、修改等。 A線性結(jié)構(gòu) B非線性結(jié)構(gòu)A 順序存儲 B 鏈?zhǔn)酱鎯?線性表棧隊樹形結(jié)構(gòu)圖形結(jié)構(gòu)數(shù)據(jù)結(jié)構(gòu)的三個主要問題 樹形結(jié)構(gòu)全校學(xué)生檔案管理的組織方式ABCDEFGH樹形結(jié)構(gòu) 結(jié)點間具有分層次的連接關(guān)系HBCDEFGA6.
2、1 樹的類型定義6.2 二叉樹的類型定義6.3 二叉樹的存儲結(jié)構(gòu)6.4 二叉樹的遍歷6.5 線索二叉樹6.6 樹和森林的表示方法6.7 樹和森林的遍歷6.8 哈夫曼樹與哈夫曼編碼6.1 樹的類型定義數(shù)據(jù)對象 D:D是具有相同特性的數(shù)據(jù)元素的集合。 若D為空集,則稱為空樹 。 否則: (1) 在D中存在唯一的稱為根的數(shù)據(jù)元素root; (2) 當(dāng)n1時,其余結(jié)點可分為m (m0)個互 不相交的有限集T1, T2, , Tm,其中每一 棵子集本身又是一棵符合本定義的樹, 稱為根root的子樹。 數(shù)據(jù)關(guān)系 R:ABCDEFGHIJMKLA( B(E, F(K, L), C(G), D(H, I, J
3、(M) )T1T3T2樹根例如: 基本操作:查 找 類 插 入 類刪 除 類 Root(T) / 求樹的根結(jié)點 查找類:Value(T, cur_e) / 求當(dāng)前結(jié)點的元素值 Parent(T, cur_e) / 求當(dāng)前結(jié)點的雙親結(jié)點LeftChild(T, cur_e) / 求當(dāng)前結(jié)點的最左孩子 RightSibling(T, cur_e) / 求當(dāng)前結(jié)點的右兄弟TreeEmpty(T) / 判定樹是否為空樹 TreeDepth(T) / 求樹的深度TraverseTree( T, Visit() ) / 遍歷InitTree(&T) / 初始化置空樹 插入類:CreateTree(&T,
4、definition) / 按定義構(gòu)造樹Assign(T, cur_e, value) / 給當(dāng)前結(jié)點賦值InsertChild(&T, &p, i, c) / 將以c為根的樹插入為結(jié)點p的第i棵子樹 ClearTree(&T) / 將樹清空 刪除類:DestroyTree(&T) / 銷毀樹的結(jié)構(gòu)DeleteChild(&T, &p, i) / 刪除結(jié)點p的第i棵子樹對比樹型結(jié)構(gòu)和線性結(jié)構(gòu)的結(jié)構(gòu)特點線性結(jié)構(gòu)樹型結(jié)構(gòu)第一個數(shù)據(jù)元素 (無前驅(qū)) 根結(jié)點 (無前驅(qū))最后一個數(shù)據(jù)元素 (無后繼)多個葉子結(jié)點 (無后繼)其它數(shù)據(jù)元素(一個前驅(qū)、 一個后繼)其它數(shù)據(jù)元素(一個前驅(qū)、 多個后繼)基 本 術(shù)
5、 語結(jié)點:結(jié)點的度:樹的度:葉子結(jié)點:分支結(jié)點:數(shù)據(jù)元素+若干指向子樹的分支分支的個數(shù)樹中所有結(jié)點的度的最大值度為零的結(jié)點度大于零的結(jié)點DHIJM(從根到結(jié)點的)路徑:孩子結(jié)點、雙親結(jié)點兄弟結(jié)點、堂兄弟祖先結(jié)點、子孫結(jié)點結(jié)點的層次:樹的深度: 由從根到該結(jié)點所經(jīng)分支和結(jié)點構(gòu)成ABCDEFGHIJMKL假設(shè)根結(jié)點的層次為1,第l 層的結(jié)點的子樹根結(jié)點的層次為l+1樹中葉子結(jié)點所在的最大層次任何一棵非空樹是一個二元組 Tree = (root,F(xiàn))其中:root 被稱為根結(jié)點 F 被稱為子樹森林森林:是m(m0)棵互不相交的樹的集合ArootBCDEFGHIJMKLF6.2 二叉樹的類型定義 二叉
6、樹或為空樹,或是由一個根結(jié)點加上兩棵分別稱為左子樹和右子樹的、互不交的二叉樹組成。ABCDEFGHK根結(jié)點左子樹右子樹二叉樹的五種基本形態(tài):N空樹只含根結(jié)點NNNLRR右子樹為空樹L左子樹為空樹左右子樹均不為空樹 二叉樹的主要基本操作:查 找 類插 入 類刪 除 類 Root(T); Value(T, e); Parent(T, e); LeftChild(T, e); RightChild(T, e); LeftSibling(T, e); RightSibling(T, e); BiTreeEmpty(T); BiTreeDepth(T); PreOrderTraverse(T, Visi
7、t(); InOrderTraverse(T, Visit(); PostOrderTraverse(T, Visit(); LevelOrderTraverse(T, Visit(); InitBiTree(&T); Assign(T, &e, value); CreateBiTree(&T, definition); InsertChild(T, p, LR, c);ClearBiTree(&T); DestroyBiTree(&T);DeleteChild(T, p, LR);二叉樹的重要特性 性質(zhì) 1 : 在二叉樹的第 i 層上至多有2i-1 個結(jié)點。 (i1)用歸納法證明: 歸納基:
8、 歸納假設(shè): 歸納證明:i = 1 層時,只有一個根結(jié)點: 2i-1 = 20 = 1;假設(shè)對所有的 j,1 j i,命題成立;二叉樹上每個結(jié)點至多有兩棵子樹,則第 i 層的結(jié)點數(shù) = 2i-2 2 = 2i-1 。性質(zhì) 2 : 深度為 k 的二叉樹上至多含 2k-1 個結(jié)點(k1)。證明: 基于上一條性質(zhì),深度為 k 的二叉樹上的結(jié)點數(shù)至多為 20+21+ +2k-1 = 2k-1 。 性質(zhì) 3 : 對任何一棵二叉樹,若它含有n0 個葉子結(jié)點、n2 個度為 2 的結(jié)點,則必存在關(guān)系式:n0 = n2+1。證明:設(shè) 二叉樹上結(jié)點總數(shù) n = n0 + n1 + n2又 二叉樹上分支總數(shù) b =
9、 n1+2n2 而 b = n-1 = n0 + n1 + n2 - 1由此, n0 = n2 + 1 。兩類特殊的二叉樹:滿二叉樹:指的是深度為k且含有2k-1個結(jié)點的二叉樹。完全二叉樹:樹中所含的 n 個結(jié)點和滿二叉樹中編號為 1 至 n 的結(jié)點一一對應(yīng)。123456789101112131415abcdefghij性質(zhì) 4 : 具有 n 個結(jié)點的完全二叉樹的深度為 log2n +1 。證明:設(shè)完全二叉樹的深度為 k 則根據(jù)第二條性質(zhì)得 2k-1 n 2k 即 k-1 log2 n n,則該結(jié)點無左孩子, 否則,編號為 2i 的結(jié)點為其左孩子結(jié)點;(3) 若 2i+1n,則該結(jié)點無右孩子結(jié)
10、點, 否則,編號為2i+1 的結(jié)點為其右孩子結(jié)點。( )例題1: 若一樹二叉共有1001個結(jié)點,且無度為1的結(jié)點,則葉子結(jié)點的個數(shù)為( )。例題2: 將一棵有100個結(jié)點的完全二叉樹從上到下,從左到右依次對結(jié)點進(jìn)行編號,根結(jié)點的編號為1,則編號為49的結(jié)點的孩子編號為( ) 。6.3 二叉樹的存儲結(jié)構(gòu)二、二叉樹的鏈?zhǔn)?存儲表示一、 二叉樹的順序 存儲表示#define MAX_TREE_SIZE 100 / 二叉樹的最大結(jié)點數(shù)typedef TElemType SqBiTreeMAX_ TREE_SIZE; / 0號單元存儲根結(jié)點SqBiTree bt;一、 二叉樹的順序存儲表示例如:ABCD
11、EF A B D C E F 0 1 2 3 4 5 6 7 8 9 10 11 12 131401326順序存儲結(jié)構(gòu)僅適用于完全二叉樹!二、二叉樹的鏈?zhǔn)酱鎯Ρ硎?. 二叉鏈表2三叉鏈表3雙親鏈表4線索鏈表ADEBCFrootlchild data rchild結(jié)點結(jié)構(gòu):1. 二叉鏈表typedef struct BiTNode / 結(jié)點結(jié)構(gòu) TElemType data; struct BiTNode *lchild, *rchild; / 左右孩子指針 BiTNode, *BiTree;lchild data rchild結(jié)點結(jié)構(gòu):C 語言的類型描述如下:ADEBCFroot2三叉鏈表pa
12、rent lchild data rchild結(jié)點結(jié)構(gòu): typedef struct TriTNode / 結(jié)點結(jié)構(gòu) TElemType data; struct TriTNode *lchild, *rchild; / 左右孩子指針 struct TriTNode *parent; /雙親指針 TriTNode, *TriTree;parent lchild data rchild結(jié)點結(jié)構(gòu):C 語言的類型描述如下:0123456 data parent結(jié)點結(jié)構(gòu):3雙親鏈表LRTagLRRRL typedef struct BPTNode / 結(jié)點結(jié)構(gòu) TElemType data; int
13、 *parent; / 指向雙親的指針 char LRTag; / 左、右孩子標(biāo)志域 BPTNode typedef struct BPTree / 樹結(jié)構(gòu) BPTNode nodesMAX_TREE_SIZE; int num_node; / 結(jié)點數(shù)目 int root; / 根結(jié)點的位置 BPTree6.4二叉樹的遍歷一、問題的提出二、先左后右的遍歷算法三、算法的遞歸描述四、中序遍歷算法的非遞歸描述五、遍歷算法的應(yīng)用舉例 如何順著某一條搜索路徑巡訪二叉樹中的結(jié)點,使得每個結(jié)點均被訪問一次,而且僅被訪問一次。一、問題的提出 “訪問”的含義可以很廣,如:輸出結(jié)點的信息等。 “遍歷”是任何類型均
14、有的操作,對線性結(jié)構(gòu)而言,只有一條搜索路徑(因為每個結(jié)點均只有一個后繼),故不需要另加討論。而二叉樹是非線性結(jié)構(gòu), 每個結(jié)點有兩個后繼,則存在如何遍歷即按什么樣的搜索路徑遍歷的問題。 對“二叉樹”而言,可以有三條搜索路徑:1先上后下的按層次遍歷;2先左(子樹)后右(子樹)的遍歷;3先右(子樹)后左(子樹)的遍歷。二、先左后右的遍歷算法先序(根)的遍歷算法中序(根)的遍歷算法后序(根)的遍歷算法 若二叉樹為空樹,則空操作;否則,(1)訪問根結(jié)點;(2)先序遍歷左子樹;(3)先序遍歷右子樹。先序(根)的遍歷算法: 若二叉樹為空樹,則空操作;否則,(1)中序遍歷左子樹;(2)訪問根結(jié)點;(3)中序遍
15、歷右子樹。中序(根)的遍歷算法: 若二叉樹為空樹,則空操作;否則,(1)后序遍歷左子樹;(2)后序遍歷右子樹;(3)訪問根結(jié)點。后序(根)的遍歷算法:課堂提問:有以下結(jié)構(gòu)的二叉樹寫出其先序、中序和后序遍歷的序列ABCDE三、算法的遞歸描述void Preorder (BiTree T, void( *visit)(TElemType& e) / 先序遍歷二叉樹 if (T) visit(T-data); / 訪問結(jié)點 Preorder(T-lchild, visit); / 遍歷左子樹 Preorder(T-rchild, visit);/ 遍歷右子樹 四、中序遍歷算法的非遞歸描述BiTNod
16、e *GoFarLeft(BiTree T, Stack *S) if (!T ) return NULL; while (T-lchild ) Push(S, T); T = T-lchild; return T;void Inorder_I(BiTree T, void (*visit) (TelemType& e) Stack *S; t = GoFarLeft(T, S); / 找到最左下的結(jié)點 while(t) visit(t-data); if (t-rchild) t = GoFarLeft(t-rchild, S); else if ( !StackEmpty(S ) / 棧不
17、空時退棧 t = Pop(S); else t = NULL; / ??毡砻鞅闅v結(jié)束 / while/ Inorder_I 五、遍歷算法的應(yīng)用舉例1、統(tǒng)計二叉樹中葉子結(jié)點的個數(shù) (先序遍歷)2、求二叉樹的深度(后序遍歷)3、復(fù)制二叉樹(后序遍歷)4、建立二叉樹的存儲結(jié)構(gòu)1、統(tǒng)計二叉樹中葉子結(jié)點的個數(shù)算法基本思想: 先序(或中序或后序)遍歷二叉樹,在遍歷過程中查找葉子結(jié)點,并計數(shù)。由此,需在遍歷算法中增添一個“計數(shù)”的參數(shù),并將算法中“訪問結(jié)點”的操作改為:若是葉子,則計數(shù)器增1。void CountLeaf (BiTree T, int& count) if ( T ) if (!T-lchi
18、ld)& (!T-rchild) count+; / 對葉子結(jié)點計數(shù) CountLeaf( T-lchild, count); CountLeaf( T-rchild, count); / if / CountLeaf2、求二叉樹的深度(后序遍歷)算法基本思想: 從二叉樹深度的定義可知,二叉樹的深度應(yīng)為其左、右子樹深度的最大值加1。由此,需先分別求得左、右子樹的深度,算法中“訪問結(jié)點”的操作為:求得左、右子樹深度的最大值,然后加 1 。 首先分析二叉樹的深度和它的左、右子樹深度之間的關(guān)系。int Depth (BiTree T ) / 返回二叉樹的深度 if ( !T ) depthval =
19、 0; else depthLeft = Depth( T-lchild ); depthRight= Depth( T-rchild ); depthval = 1 + (depthLeft depthRight ? depthLeft : depthRight); return depthval;3、復(fù)制二叉樹其基本操作為:生成一個結(jié)點。根元素T左子樹右子樹根元素NEWT左子樹右子樹左子樹右子樹(后序遍歷)BiTNode *GetTreeNode(TElemType item, BiTNode *lptr , BiTNode *rptr ) if (!(T = (BiTNode*)mall
20、oc(sizeof(BiTNode) exit(OVERFLOW); T- data = item; T- lchild = lptr; T- rchild = rptr; return T; 生成一個二叉樹的結(jié)點(其數(shù)據(jù)域為item,左指針域為lptr,右指針域為rptr)BiTNode *CopyTree(BiTNode *T) if (!T ) return NULL; if (T-lchild ) newlptr = CopyTree(T-lchild);/復(fù)制左子樹 else newlptr = NULL; if (T-rchild ) newrptr = CopyTree(T-rc
21、hild);/復(fù)制右子樹 else newrptr = NULL; newT = GetTreeNode(T-data, newlptr, newrptr); return newT; / CopyTreeABCDEFGHK D C B H K G F E A例如:下列二叉樹的復(fù)制過程如下:newT4、建立二叉樹的存儲結(jié)構(gòu)不同的定義方法相應(yīng)有不同的存儲結(jié)構(gòu)的建立算法以字符串“A!”表示 以字符串的形式 根 左子樹 右子樹定義一棵二叉樹例如:ABCD以字符“!”表示A(B(! ,C(! , ! ),D(! , ! )空樹只含一個根結(jié)點的二叉樹A以下列字符串表示Status CreateBiTre
22、e(BiTree &T) scanf(&ch); if (ch=!) T = NULL; else if (!(T = (BiTNode *)malloc(sizeof(BiTNode) exit(OVERFLOW); T-data = ch; / 生成根結(jié)點 CreateBiTree(T-lchild); / 構(gòu)造左子樹 CreateBiTree(T-rchild); / 構(gòu)造右子樹 return OK; / CreateBiTree 僅知二叉樹的先序序列“abcdefg” 不能唯一確定一棵二叉樹,由二叉樹的先序和中序序列建樹 如果同時已知二叉樹的中序序列“cbdaegf”,則會如何? 二叉
23、樹的先序序列二叉樹的中序序列左子樹左子樹右子樹右子樹根根a b c d e f gc b d a e g f例如:aab bccddeeffggabcdefg先序序列中序序列void CrtBT(BiTree& T, char pre, char ino, int ps, int is, int n ) / 已知preps.ps+n-1為二叉樹的先序序列, / inois.is+n-1為二叉樹的中序序列,本算 / 法由此兩個序列構(gòu)造二叉鏈表 if (n=0) T=NULL; else k=Search(ino, preps); / 在中序序列中查詢 if (k= -1) T=NULL; els
24、e / / CrtBT T=(BiTNode*)malloc(sizeof(BiTNode);T-data = preps;if (k=is) T-Lchild = NULL;else CrtBT(T-Lchild, pre, ino, ps+1, is, k-is );if (k=is+n-1) T-Rchild = NULL;else CrtBT(T-Rchild, pre, ino, ps+(k-is)+1, k+1, n-(k-is)-1 );例題:1、編寫遞歸算法:對于二叉樹中每一個元素值為x的結(jié)點,刪除以它為根的子樹,并釋放相應(yīng)的空間。6.5線索二叉樹 何謂線索二叉樹? 線索鏈表的
25、遍歷算法 如何建立線索鏈表?一、何謂線索二叉樹?遍歷二叉樹的結(jié)果是, 求得結(jié)點的一個線性序列。ABCDEFGHK例如:先序序列: A B C D E F G H K中序序列: B D C A H G K F E后序序列: D C B H K G F E A指向該線性序列中的“前驅(qū)”和“后繼” 的指針,稱作“線索”與其相應(yīng)的二叉樹,稱作 “線索二叉樹”包含 “線索” 的存儲結(jié)構(gòu),稱作 “線索鏈表”A B C D E F G H K D C B E 對線索鏈表中結(jié)點的約定: 在二叉鏈表的結(jié)點中增加兩個標(biāo)志域,并作如下規(guī)定:若該結(jié)點的左子樹不空,則Lchild域的指針指向其左子樹, 且左標(biāo)志域的值為
26、“指針 Link”; 否則,Lchild域的指針指向其“前驅(qū)”, 且左標(biāo)志的值為“線索 Thread” 。若該結(jié)點的右子樹不空,則rchild域的指針指向其右子樹, 且右標(biāo)志域的值為 “指針 Link”;否則,rchild域的指針指向其“后繼”, 且右標(biāo)志的值為“線索 Thread”。 如此定義的二叉樹的存儲結(jié)構(gòu)稱作“線索鏈表”。typedef struct BiThrNod TElemType data; struct BiThrNode *lchild, *rchild; / 左右指針 PointerThr LTag, RTag; / 左右標(biāo)志 BiThrNode, *BiThrTree;
27、線索鏈表的類型描述: typedef enum Link, Thread PointerThr; / Link=0:指針,Thread=1:線索線索二叉樹的頭結(jié)點添加一個頭結(jié)點,并令其lchild域的指針指向二叉樹的根結(jié)點,其rchild域的指針指向中序遍歷時訪問的最后一個結(jié)點;反之,令二叉樹中序序列中的第一個結(jié)點的lchild域指針和最后一個結(jié)點rchild域 的指針均指向頭結(jié)點。這好比為二叉樹建立了一個雙向線索鏈表。(參考教材P133)二、線索鏈表的遍歷算法: for ( p = firstNode(T); p; p = Succ(p) ) Visit (p);由于在線索鏈表中添加了遍歷中
28、得到的“前驅(qū)”和“后繼”的信息,從而簡化了遍歷的算法。例如: 對中序線索化鏈表的遍歷算法 中序遍歷的第一個結(jié)點 ? 在中序線索化鏈表中結(jié)點的后繼 ?左子樹上處于“最左下”(沒有左子樹)的結(jié)點。若無右子樹,則為后繼線索所指結(jié)點;否則為對其右子樹進(jìn)行中序遍歷時訪問的第一個結(jié)點。void InOrderTraverse_Thr(BiThrTree T, void (*Visit)(TElemType e) p = T-lchild; / p指向根結(jié)點 while (p != T) / 空樹或遍歷結(jié)束時,p=T while (p-LTag=Link) p = p-lchild; / 第一個結(jié)點 if
29、( !Visit( p-data ) ) return ERROR; while (p-RTag=Thread & p-rchild!=T) p = p-rchild; Visit(p-data); / 訪問后繼結(jié)點 p = p-rchild; / p進(jìn)至其右子樹根 / InOrderTraverse_Thr 在中序遍歷過程中修改結(jié)點的左、右指針域,以保存當(dāng)前訪問結(jié)點的“前驅(qū)”和“后繼”信息。遍歷過程中,附設(shè)指針pre, 并始終保持指針pre指向當(dāng)前訪問的、指針p所指結(jié)點的前驅(qū)。三、如何建立線索鏈表?void InThreading(BiThrTree p) if (p) / 對以p為根的非空
30、二叉樹進(jìn)行線索化 InThreading(p-lchild); / 左子樹線索化 if (!p-lchild) / 建前驅(qū)線索 p-LTag = Thread; p-lchild = pre; if (!pre-rchild) / 建后繼線索 pre-RTag = Thread; pre-rchild = p; pre = p; / 保持 pre 指向 p 的前驅(qū) InThreading(p-rchild); / 右子樹線索化 / if / InThreadingStatus InOrderThreading(BiThrTree &Thrt, BiThrTree T) / 構(gòu)建中序線索鏈表 i
31、f (!(Thrt = (BiThrTree)malloc( sizeof( BiThrNode) exit (OVERFLOW); Thrt-LTag = Link; Thrt-RTag =Thread; Thrt-rchild = Thrt; / 添加頭結(jié)點 return OK; / InOrderThreading if (!T) Thrt-lchild = Thrt; else Thrt-lchild = T; pre = Thrt; InThreading(T); pre-rchild = Thrt; / 處理最后一個結(jié)點 pre-RTag = Thread; Thrt-rchild
32、 = pre; 課堂練習(xí)習(xí)題集:P436.56 6.6 樹和森林 的表示方法6.6.1 樹的三種存儲結(jié)構(gòu)一、雙親表示法二、孩子鏈表表示法三、樹的二叉鏈表(孩子-兄弟) 存儲表示法ABCDEFG0 A -11 B 02 C 03 D 04 E 2 5 F 26 G 5r=0n=6data parent一、雙親表示法: typedef struct PTNode Elem data; int parent; / 雙親位置域 PTNode; data parent#define MAX_TREE_SIZE 100結(jié)點結(jié)構(gòu):C語言的類型描述:typedef struct PTNode nodes MA
33、X_TREE_SIZE; int r, n; / 根結(jié)點的位置和結(jié)點個數(shù) PTree;樹結(jié)構(gòu):ABCDEFG0 A -11 B 02 C 03 D 04 E 25 F 26 G 4r=0n=6 data firstchild 1 2 34 56二、孩子鏈表表示法:typedef struct CTNode int child; struct CTNode *next; *ChildPtr;孩子結(jié)點結(jié)構(gòu): child nextC語言的類型描述: typedef struct Elem data; ChildPtr firstchild; / 孩子鏈的頭指針 CTBox;雙親結(jié)點結(jié)構(gòu) data f
34、irstchildtypedef struct CTBox nodesMAX_TREE_SIZE; int n, r; / 結(jié)點數(shù)和根結(jié)點的位置 CTree;樹結(jié)構(gòu):ABCDEFG AB C E D F Groot AB C E D F G 三、樹的二叉鏈表 (孩子-兄弟)存儲表示法typedef struct CSNode Elem data; struct CSNode *firstchild, *nextsibling; CSNode, *CSTree;C語言的類型描述:結(jié)點結(jié)構(gòu): firstchild data nextsibling 6.6.2 森林和二叉樹的轉(zhuǎn)換設(shè)森林 F = (
35、T1, T2, , Tn ); T1 = (root,t11, t12, , t1m);二叉樹 B =( LBT, Node(root), RBT ); 由于二叉樹可以用二叉鏈表表示,為了使一般樹也能用二叉鏈表表示,必須找出樹與二叉樹之間的關(guān)系。 這樣,給定一棵樹,可以找到唯一的一棵二叉樹與之對應(yīng)。方法: 對每個孩子進(jìn)行從左到右的排序; 在兄弟之間加一條連線; 對每個結(jié)點,除了左孩子外,去除其與其余孩子之間的聯(lián)系; 以根結(jié)點為軸心,將整個樹順時針轉(zhuǎn)45度。1、將樹轉(zhuǎn)換成二叉樹的轉(zhuǎn)換規(guī)則為: I A B C DE F G H(b) A B CD E G H FI(a)樹轉(zhuǎn)換為二叉樹ABEFCDG
36、HI(d)ABCDEFGHI(c)2、由森林轉(zhuǎn)換成二叉樹的轉(zhuǎn)換規(guī)則為:若 F = ,則 B = ;否則, 由 ROOT( T1 ) 對應(yīng)得到 Node(root); 由 (t11, t12, , t1m ) 對應(yīng)得到 LBT; 由 (T2, T3, Tn ) 對應(yīng)得到 RBT。森林轉(zhuǎn)換為二叉樹ADCBEFHIGJEFADCBHIGJADCBEFHIGJADCBEFHIGJ3、由二叉樹轉(zhuǎn)換為森林的轉(zhuǎn)換規(guī)則為:若 B = , 則 F = ;否則,由 Node(root) 對應(yīng)得到 ROOT( T1 );由LBT 對應(yīng)得到 ( t11, t12, ,t1m);由RBT 對應(yīng)得到 (T2, T3, ,
37、 Tn)。將二叉樹轉(zhuǎn)換成樹或森林的方法如下:1.若某結(jié)點是其雙親的左孩子,則把該結(jié)點的右孩子、右孩子的右孩子都與該結(jié)點的雙親結(jié)點用線連起來;2.刪除原二叉樹中所有的雙親結(jié)點與右孩子結(jié)點的連線.3.整理步驟1、2所得到的樹或森林,使結(jié)構(gòu)層次分明.將二叉樹轉(zhuǎn)換為樹或森林的另一種描述:ABEFCDGHI(a)ABEFCDGHI(b)將二叉樹轉(zhuǎn)換為樹或森林ABEFCDGHI(c) 若某結(jié)點是其雙親的左孩子,則把該結(jié)點的右孩子、右孩子的右孩子都與該結(jié)點的雙親結(jié)點用線連起來;刪除原二叉樹中所有的雙親結(jié)點與右孩子結(jié)點的連線. 由此,樹的各種操作均可對應(yīng)二叉樹的操作來完成。 應(yīng)當(dāng)注意的是,和樹對應(yīng)的二叉樹,其
38、左、右子樹的概念已改變?yōu)椋?左是孩子,右是兄弟。6.7樹和森林的遍歷一、樹的遍歷二、森林的遍歷三、樹的遍歷的應(yīng)用樹的遍歷可有三條搜索路徑:按層次遍歷:先根(次序)遍歷:后根(次序)遍歷: 若樹不空,則先訪問根結(jié)點,然后依次先根遍歷各棵子樹。 若樹不空,則先依次后根遍歷各棵子樹,然后訪問根結(jié)點。 若樹不空,則自上而下自左至右訪問樹中每個結(jié)點。 A B C DE F G H I J K 先根遍歷時頂點的訪問次序:A B E F C D G H I J K 后根遍歷時頂點的訪問次序:E F B C I J K H G D A 層次遍歷時頂點的訪問次序:A B C D E F G H I J K B
39、C DE F G H I J K1森林中第一棵樹的根結(jié)點;2森林中第一棵樹的子樹森林;3森林中其它樹構(gòu)成的森林。森林由三部分構(gòu)成: 若森林不空,則訪問森林中第一棵樹的根結(jié)點;先序遍歷森林中第一棵樹的子樹森林;先序遍歷森林中(除第一棵樹之外)其 余樹構(gòu)成的森林。1. 先序遍歷森林的遍歷即:依次從左至右對森林中的每一棵樹進(jìn)行先根遍歷。中序遍歷 若森林不空,則中序遍歷森林中第一棵樹的子樹森林;訪問森林中第一棵樹的根結(jié)點;中序遍歷森林中(除第一棵樹之外)其 余樹構(gòu)成的森林。即:依次從左至右對森林中的每一棵樹進(jìn)行后根遍歷。 樹的遍歷和二叉樹遍歷的對應(yīng)關(guān)系 ?先根遍歷后根遍歷樹二叉樹森林先序遍歷先序遍歷中
40、序遍歷后序遍歷設(shè)樹的存儲結(jié)構(gòu)為孩子兄弟鏈表typedef struct CSNode Elem data; struct CSNode *firstchild, *nextsibling; CSNode, *CSTree;一、求樹的深度二、輸出樹中所有從根到葉子的路徑三、建樹的存儲結(jié)構(gòu)int TreeDepth(CSTree T) if(!T) return 0; else h1 = TreeDepth( T-firstchild ); h2 = TreeDepth( T-nextsibling); / TreeDepthreturn(max(h1+1, h2);一、求樹的深度的算法:二、輸出
41、樹中所有從根到葉子的路徑的算法: A B C DE F G H I J K例如:對左圖所示的樹,其輸出結(jié)果應(yīng)為:A B EA B FA CA D G H IA D G H JA D G H Kvoid AllPath( Bitree T, Stack& S ) if (T) Push( S, T-data ); if (!T-Lchild & !T-Rchild ) PrintStack(S); else AllPath( T-Lchild, S ); AllPath( T-Rchild, S ); Pop(S); / if(T) / AllPath/ 輸出二叉樹上從根到所有葉子結(jié)點的路徑vo
42、id OutPath( Bitree T, Stack& S ) while ( !T ) Push(S, T-data ); if ( !T-firstchild ) Printstack(s); else OutPath( T-firstchild, s ); Pop(S); T = T-nextsibling; / while / OutPath/ 輸出森林中所有從根到葉的路徑三、建樹的存儲結(jié)構(gòu)的算法: 和二叉樹類似,不同的定義相應(yīng)有不同的算法。 假設(shè)以二元組(F,C)的形式自上而下、自左而右依次輸入樹的各邊,建立樹的孩子-兄弟鏈表。ABCDEFG例如:對下列所示樹的輸入序列應(yīng)為:(#,
43、 A)(A, B)(A, C)(A, D)(C, E)(C, F)(E, G)ABCD(#, A)(A, B)(A, C)(A, D)(C, E)可見,算法中需要一個隊列保存已建好的結(jié)點的指針。void CreatTree( CSTree &T ) T = NULL; for( scanf(&fa, &ch); ch!= ; scanf(&fa, &ch);) p = GetTreeNode(ch); / 創(chuàng)建結(jié)點EnQueue(Q, p); / 指針入隊列if (fa = ) T = p; / 所建為根結(jié)點 else / 非根結(jié)點的情況 / for / CreateTree GetHead(
44、Q,s); / 取隊列頭元素(指針值)while (s-data != fa ) / 查詢雙親結(jié)點 DeQueue(Q,s); GetHead(Q,s); if (!(s-firstchild) s-firstchild = p; r = p; / 鏈接第一個孩子結(jié)點else r-nextsibling = p; r = p; / 鏈接其它孩子結(jié)點 習(xí)題:配套習(xí)題集P44:6.58、6.60、6.666.8 哈 夫 曼 樹 與 哈 夫 曼 編 碼 最優(yōu)樹的定義 如何構(gòu)造最優(yōu)樹 前綴編碼 一、最優(yōu)樹的定義樹的路徑長度定義為: 樹中每個結(jié)點的路徑長度之和。 結(jié)點的路徑長度定義為: 從根結(jié)點到該結(jié)點
45、的路徑上 分支的數(shù)目。1245367PL=0+1+1+2+2+2+2=10樹的路徑長度用PL表示。1245C67PL=0+1+1+2+2+3+3=12 樹的帶權(quán)路徑長度定義為: 樹中所有葉子結(jié)點的帶權(quán)路徑長度之和 WPL(T) = wkLk (對所有葉子結(jié)點)。其中:Wk為樹中每個葉子結(jié)點的權(quán); Lk為每個葉子結(jié)點到根的路徑長度。例如:27 9 75492WPL(T)= 72+52+23+43+92 =60WPL(T)= 74+94+53+42+21 =89 54最優(yōu)樹 在所有含 n 個葉子結(jié)點、并帶相同權(quán)值的 m 叉樹中,必存在一棵其帶權(quán)路徑長度取最小值的樹,稱為“最優(yōu)樹”。27 9 754
46、92WPL(T)= 72+52+23+43+92 =60WPL(T)= 74+94+53+42+21 =89 54 由原始數(shù)據(jù)生成森林 根據(jù)給定的n個權(quán)值 w1, w2, , wn, 構(gòu)造 n 棵二叉樹的集合 F = T1, T2, , Tn, 其中每棵二叉樹中均只含一個帶權(quán)值 為 wi 的根結(jié)點,其左、右子樹為空樹;二、如何構(gòu)造最優(yōu)樹(1)(哈夫曼算法) 以二叉樹為例: 在 F 中選取其根結(jié)點的權(quán)值為最 小的兩棵二叉樹,分別作為左、 右子樹構(gòu)造一棵新的二叉樹,并 置這棵新的二叉樹根結(jié)點的權(quán)值 為其左、右子樹根結(jié)點的權(quán)值之 和;(2) 從F中刪去這兩棵樹,同時加入 剛生成的新樹; 重復(fù) (2)
47、 和 (3) 兩步,直至 F 中只 含一棵樹為止。(3)(4)675cd(b)11b57cd(c)18a711cdb5624(d)abcd7524(a)例:給定權(quán)值7,5,2,4,構(gòu)造哈夫曼樹。9例: 已知權(quán)值 W= 5, 6, 2, 9, 7 ,構(gòu)造哈夫曼樹。5627527697671395276713952795271667132900001111000110110111三、哈夫曼樹的應(yīng)用1、判定樹 在解決某些判定問題時,利用哈夫曼樹可以得到最佳判定算法。例1 將學(xué)生百分成績按分?jǐn)?shù)段分級的程序。若學(xué)生成績分布是均勻的,可用圖(a)二叉樹結(jié)構(gòu)來實現(xiàn)。 a60 a70 a80 a90 不及格中等良好優(yōu)秀及格YNYNYNYN(a)輸入10000個數(shù)據(jù),則需進(jìn)行31500次比較。分?jǐn)?shù)0596069707980899099比例0.050.150.40.30
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 廣元市青川縣考調(diào)事業(yè)單位人員真題2024
- 文獻(xiàn)挖掘與知識圖譜-全面剖析
- 智能視頻監(jiān)控算法-全面剖析
- 2025年導(dǎo)游資格證考試筆試模擬試卷:全國旅游景點導(dǎo)游詞編寫技巧試題
- 物聯(lián)網(wǎng)數(shù)據(jù)隱私保護(hù)-第7篇-全面剖析
- 當(dāng)代藝術(shù)市場趨勢-第1篇-全面剖析
- 旅游產(chǎn)業(yè)融合趨勢-全面剖析
- 2025年鋼琴演奏級考試模擬試卷:鋼琴演奏藝術(shù)修養(yǎng)與審美能力試題
- 2025-2030全球及中國海灣合作委員會國家預(yù)灌漿行業(yè)市場現(xiàn)狀供需分析及市場深度研究發(fā)展前景及規(guī)劃可行性分析研究報告
- 2025-2030全球及中國汽車底盤測功機(jī)行業(yè)市場現(xiàn)狀供需分析及市場深度研究發(fā)展前景及規(guī)劃可行性分析研究報告
- 易制毒、易制爆化學(xué)品安全培訓(xùn)
- 美女金喜善寫真集
- 入伍簡歷當(dāng)兵簡歷.doc
- 前列腺癌臨床路徑(最全版)
- 國家旅游局新版團(tuán)隊出境旅游合同模板
- 4S店三表一卡標(biāo)準(zhǔn)模板
- 南京地鐵四號線風(fēng)井主體結(jié)構(gòu)施工方案
- 高中生物競賽 第九章 染色體畸變課件
- 四年級下冊《小數(shù)的意義和性質(zhì)》整理和復(fù)習(xí)
- 土壤污染修復(fù)技術(shù)對比分析
- 3萬高爐轉(zhuǎn)爐混合煤氣柜技術(shù)規(guī)程
評論
0/150
提交評論