![數(shù)據(jù)結(jié)構(gòu)第六章樹_第1頁](http://file2.renrendoc.com/fileroot_temp3/2021-11/12/f80a9e6a-2d96-4404-9495-18e6af7a0082/f80a9e6a-2d96-4404-9495-18e6af7a00821.gif)
![數(shù)據(jù)結(jié)構(gòu)第六章樹_第2頁](http://file2.renrendoc.com/fileroot_temp3/2021-11/12/f80a9e6a-2d96-4404-9495-18e6af7a0082/f80a9e6a-2d96-4404-9495-18e6af7a00822.gif)
![數(shù)據(jù)結(jié)構(gòu)第六章樹_第3頁](http://file2.renrendoc.com/fileroot_temp3/2021-11/12/f80a9e6a-2d96-4404-9495-18e6af7a0082/f80a9e6a-2d96-4404-9495-18e6af7a00823.gif)
![數(shù)據(jù)結(jié)構(gòu)第六章樹_第4頁](http://file2.renrendoc.com/fileroot_temp3/2021-11/12/f80a9e6a-2d96-4404-9495-18e6af7a0082/f80a9e6a-2d96-4404-9495-18e6af7a00824.gif)
![數(shù)據(jù)結(jié)構(gòu)第六章樹_第5頁](http://file2.renrendoc.com/fileroot_temp3/2021-11/12/f80a9e6a-2d96-4404-9495-18e6af7a0082/f80a9e6a-2d96-4404-9495-18e6af7a00825.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、6.1 樹的類型定義樹的類型定義6.2 二叉樹二叉樹6.3 遍歷和線索二叉樹遍歷和線索二叉樹6.4 樹和森林樹和森林6.5 樹與等價問題樹與等價問題6.6 哈夫曼樹及其應用哈夫曼樹及其應用6.1 樹的類型定義樹的類型定義數(shù)據(jù)對象數(shù)據(jù)對象 d:d是具有相同特性的數(shù)據(jù)元素的集合。是具有相同特性的數(shù)據(jù)元素的集合。 若若d為空集,則稱為空樹;為空集,則稱為空樹; 否則否則: (1) 在在d中存在唯一的稱為根的數(shù)據(jù)元素中存在唯一的稱為根的數(shù)據(jù)元素root, (2) 當當n1時,其余結(jié)點可分為時,其余結(jié)點可分為m (m0)個互個互 不相交的有限集不相交的有限集t1, t2, , tm, 其中每一其中每一
2、棵子集本身又是一棵符合本定義的樹,棵子集本身又是一棵符合本定義的樹, 稱為根稱為根root的子樹。的子樹。 數(shù)據(jù)關(guān)系數(shù)據(jù)關(guān)系 r:abcdefghijmkla( )t1t3t2樹根例如例如: :b(e, f(k, l), c(g), d(h, i, j(m)樹具有下面兩個特點:樹具有下面兩個特點:(1 1)樹的根結(jié)點沒有前驅(qū)結(jié)點,)樹的根結(jié)點沒有前驅(qū)結(jié)點,除根結(jié)點之外的所有結(jié)點有且除根結(jié)點之外的所有結(jié)點有且只有一個前驅(qū)結(jié)點。只有一個前驅(qū)結(jié)點。(2 2)樹中所有結(jié)點可以有零個)樹中所有結(jié)點可以有零個或多個后繼結(jié)點?;蚨鄠€后繼結(jié)點。() 有確定的根;() 樹根和子樹根之間為有向關(guān)系。有向樹:有向樹
3、:有序樹:有序樹:子樹之間存在確定的次序關(guān)系。無序樹:無序樹:子樹之間不存在確定的次序關(guān)系。基基 本本 術(shù)術(shù) 語語(從根到結(jié)點的)路徑路徑:結(jié)點的層次結(jié)點的層次: :樹的深度:樹的深度: 由從根根到該結(jié)點所經(jīng)分支和結(jié)點構(gòu)成abcdefghijmkl假設(shè)根結(jié)點的層次為1,第l 層的結(jié)點的子樹根結(jié)點的層次為l+1樹中葉子結(jié)點所在的最大層次任何一棵非空樹是一個二元組 tree = (root,f)其中:其中:root 被稱為根結(jié)點, f 被稱為子樹森林森林:森林:是 m(m0)棵互不相交的樹的集合arootbefklcgdhijmf對比對比樹型結(jié)構(gòu)樹型結(jié)構(gòu)和和線性結(jié)構(gòu)線性結(jié)構(gòu)的結(jié)構(gòu)特點的結(jié)構(gòu)特點線性
4、結(jié)構(gòu)線性結(jié)構(gòu)樹型結(jié)構(gòu)樹型結(jié)構(gòu)第一個數(shù)據(jù)元素第一個數(shù)據(jù)元素 ( (無前驅(qū)無前驅(qū)) ) 根結(jié)點根結(jié)點 ( (無前驅(qū)無前驅(qū)) )最后一個數(shù)據(jù)元素最后一個數(shù)據(jù)元素 (無后繼無后繼)多個葉子結(jié)點多個葉子結(jié)點 ( (無后繼無后繼) )其它數(shù)據(jù)元素其它數(shù)據(jù)元素( (一個前驅(qū)、一個前驅(qū)、 一個后繼一個后繼) )其它數(shù)據(jù)元素其它數(shù)據(jù)元素( (一個前驅(qū)、一個前驅(qū)、 多個后繼多個后繼) )6.2 二叉樹的類型定義二叉樹的類型定義 二叉樹或為空樹空樹;或是由一個根結(jié)根結(jié)點點加上兩棵兩棵分別稱為左子樹左子樹和右子樹的、互不交的互不交的二叉樹二叉樹組成。abcdefghk根結(jié)點左子樹右子樹ef二叉樹的五種基本形態(tài):二叉樹
5、的五種基本形態(tài):n空樹空樹只含根結(jié)點只含根結(jié)點nnnlrr右子樹為空樹右子樹為空樹l左子樹為空樹左子樹為空樹左右子左右子樹均不樹均不為空樹為空樹二叉樹二叉樹的重要特性的重要特性 性質(zhì)性質(zhì) 1 : 在二叉樹的第 i 層上至多有2i-1 個結(jié)點。 (i1)用歸納法用歸納法證明證明: 歸納基歸納基: 歸納假設(shè):歸納假設(shè): 歸納證明:歸納證明:i = 1 層時,只有一個根結(jié)點, 2i-1 = 20 = 1;假設(shè)對所有的 j,1 j i,命題成立;二叉樹上每個結(jié)點至多有兩棵子樹,則第 i 層的結(jié)點數(shù) = 2i-2 2 = 2i-1 。 性質(zhì)性質(zhì) 2 : 深度為 k 的二叉樹上至多含 2k-1 個結(jié)點(k
6、1)證明:證明: 基于上一條性質(zhì),深度為 k 的二叉樹上的結(jié)點數(shù)至多為 20+21+ +2k-1 = 2k-1 性質(zhì)性質(zhì) 3 : 對任何一棵二叉樹,若它含有n0 個葉子結(jié)點、n2 個度為 2 的結(jié)點,則必存在關(guān)系式:n0 = n2+1證明:證明:設(shè)設(shè) 二叉樹上結(jié)點總數(shù) n = n0 + n1 + n2又又 二叉樹上分支總數(shù) b = n1 + 2n2而 b = n-1 = n0 + n1 + n2 - 1由此,由此, n0 = n2 + 1兩類兩類特殊特殊的二叉樹:的二叉樹:滿二叉樹滿二叉樹:指的是深度為k且含有2k-1個結(jié)點的二叉樹。完全二叉樹完全二叉樹:樹中所含的 n 個結(jié)點和滿二叉樹中編號
7、編號為為 1 至至 n 的結(jié)點的結(jié)點一一對應。123456789 10 11 12 13 14 15abcdefghij 性質(zhì)性質(zhì) 4 : 具有 n 個結(jié)點的完全二叉樹的深度深度為 log2n +1證明:證明:設(shè)設(shè) 完全二叉樹的深度為 k 則根據(jù)第二條性質(zhì)得 2k-1 n 2k 即 k-1 log2 n n,則該結(jié)點無左孩子, 否則,編號為 2i 的結(jié)點為其左孩子左孩子結(jié)點;(3) 若 2i+1n,則該結(jié)點無右孩子結(jié)點, 否則,編號為2i+1 的結(jié)點為其右孩子右孩子結(jié)點。6.2.4 二叉樹的存儲二叉樹的存儲二、二叉樹的鏈式二、二叉樹的鏈式 存儲表示存儲表示一、一、 二叉樹的順序二叉樹的順序 存
8、儲表示存儲表示一、一、 二叉樹的順序存儲表示二叉樹的順序存儲表示二叉樹的順序存儲,就是用一組連續(xù)的存儲單元存放二叉樹中的結(jié)點。一般是按照二叉樹結(jié)點從上至下、從左到右的順序存儲。例如例如: a b d c e f 0 1 2 3 4 5 6 7 8 9 10 11 12 13abcdef1401326#define maxnode 30/*二叉樹的最大結(jié)點數(shù)*/typedef elemtype sqbitreemaxnode;/* 0號單元存放根結(jié)點 */sqbitree bt;即將bt定義為含有maxnode個elemtype類型元素的一維數(shù)組。 完全二叉樹和滿二叉樹適合順序存儲完全二叉樹和滿
9、二叉樹適合順序存儲二、二叉樹的鏈式存儲表示二、二叉樹的鏈式存儲表示1. 1. 二叉鏈表二叉鏈表2三叉鏈表三叉鏈表3 3雙親鏈表雙親鏈表adebcf rootlchild data rchild結(jié)點結(jié)構(gòu)結(jié)點結(jié)構(gòu):1. 1. 二叉鏈表二叉鏈表typedef struct bitnode / 結(jié)點結(jié)構(gòu)結(jié)點結(jié)構(gòu) elemtype data; struct bitnode *lchild, *rchild; / 左右孩子指針 bitnode, *bitree;lchild data rchild結(jié)點結(jié)構(gòu)結(jié)點結(jié)構(gòu):c 語言的類型描述如下語言的類型描述如下: :rootadebcf 2三叉鏈表三叉鏈表par
10、ent lchild data rchild結(jié)點結(jié)構(gòu)結(jié)點結(jié)構(gòu): typedef struct tritnode / 結(jié)點結(jié)構(gòu)結(jié)點結(jié)構(gòu) telemtype data; struct tritnode *lchild, *rchild; / 左右孩子指針 struct tritnode *parent; /雙親指針 tritnode, *tritree;parent lchild data rchild結(jié)點結(jié)構(gòu)結(jié)點結(jié)構(gòu):c 語言的類型描述如下語言的類型描述如下: :結(jié)點結(jié)構(gòu)結(jié)點結(jié)構(gòu):3 3雙親鏈表雙親鏈表 data parentabdcef0b41d42c03e14a-15f36lrtaglrrr
11、l根根 typedef struct bptnode / 結(jié)點結(jié)構(gòu)結(jié)點結(jié)構(gòu) telemtype data; int *parent; / 指向雙親的指針 char lrtag; / 左、右孩子標志域 bptnode typedef struct bptree / 樹結(jié)構(gòu)樹結(jié)構(gòu) bptnode nodesmax_tree_size; int num_node; / 結(jié)點數(shù)目 int root; / 根結(jié)點的位置 bptree6.3.1二叉樹的遍歷二叉樹的遍歷一、問題的提出一、問題的提出二、先左后右的遍歷算法二、先左后右的遍歷算法三、算法的遞歸描述三、算法的遞歸描述四、中序遍歷算法的非遞歸描述四、
12、中序遍歷算法的非遞歸描述五五、遍歷算法的應用舉例遍歷算法的應用舉例 順著某一條搜索路徑巡訪巡訪二叉樹中的結(jié)點,使得每個結(jié)點均被訪問一均被訪問一次次,而且僅被訪問一次僅被訪問一次。一、問題的提出一、問題的提出“訪問訪問”的含義可以很廣,如:輸出結(jié)點的信息等。 “遍歷遍歷”是任何類型均有的操作,對線性結(jié)構(gòu)而言,只有一條搜索路徑(因為每個結(jié)點均只有一個后繼),故不需要另加討論。而二叉樹是非線性結(jié)構(gòu), 每個結(jié)點有兩個后繼每個結(jié)點有兩個后繼,則存在如何遍歷存在如何遍歷即按什么樣的搜索搜索路徑路徑進行進行遍歷的問題。 對對“二叉樹二叉樹”而言,可以有而言,可以有三條搜索路徑:三條搜索路徑: 1先上后下先上
13、后下的按層次遍歷; 2先左先左(子樹)后右后右(子樹)的遍歷; 3先右先右(子樹)后左后左(子樹)的遍歷。abcdefghij二、先左后右的遍歷算法二、先左后右的遍歷算法先先(根)序的遍歷算法中中(根)序的遍歷算法后后(根)序的遍歷算法根根左子樹右子樹根根根根根根根根根根 若二叉樹為空樹,則空操作;否則,(1)訪問根結(jié)點;(2)先序遍歷左子樹;(3)先序遍歷右子樹。先(根)序的遍歷算法:先(根)序的遍歷算法:adbcd l rad l rd l rbdcd l r先序遍歷序列:a b d c先序遍歷: 若二叉樹為空樹,則空操作;否則,(1)中序遍歷左子樹;(2)訪問根結(jié)點;(3)中序遍歷右子樹
14、。中(根)序的遍歷算法:中(根)序的遍歷算法:adbcl d rbl d rl d radcl d r中序遍歷序列:b d a c中序遍歷: 若二叉樹為空樹,則空操作;否則,(1)后序遍歷左子樹;(2)后序遍歷右子樹;(3)訪問根結(jié)點。后(根)序的遍歷算法:后(根)序的遍歷算法:adbc l r dl r dl r dadcl r d后序遍歷序列: d b c a后序遍歷:b-+/a*b-efcd先序遍歷:中序遍歷:后序遍歷:層次遍歷:- + a * b - c d / e f-+a*b-cd/ef-+ a*b-cd/ef-+a*b-c d/e fabcdefghk例如:例如:先序序列:先序序
15、列:中序序列:中序序列:后序序列:后序序列:a b c d e f g h kb d c a e h g k fd c b h k g f e a三、算法的遞歸描述三、算法的遞歸描述void preorder (bitree t, void( *visit)(telemtype& e) / 先序遍歷二叉樹 if (t) visit(t-data); / 訪問結(jié)點 preorder(t-lchild, visit); / 遍歷左子樹 preorder(t-rchild, visit);/ 遍歷右子樹 void preorder(jd *bt) if(bt!=null) printf(%d
16、t,bt-data); preorder(bt-lchild); preorder(bt-rchild); 主程序主程序pre( t )返回返回pre(t r);返回返回pre(t r);acbdtbprintf(b);pre(t l);btaprintf(a);pre(t l);atdprintf(d);pre(t l);dtcprintf(c);pre(t l);c返回t左是空返回pre(t r);t左是空返回t右是空返回t左是空返回t右是空返回pre(t r);先序序列:a b d c中序遍歷 void inorder(jd *bt) if(bt!=null) inorder(bt-lc
17、hild); printf(%dt,bt-data); inorder(bt-rchild); 后序遍歷 void postorder(jd *bt) if(bt!=null) postorder(bt-lchild); postorder(bt-rchild); printf(%dt,bt-data); 中序遍歷算法的非遞歸描述中序遍歷算法的非遞歸描述有兩種分析(描述)方法:一、“任務書”分析方法二、“路徑”分析方法在寫算法之前首先需定義棧的元素類型。typedeftypedef enum travel, visit tasktype; / travel = 1:遍歷, / visit =
18、0:訪問 typedef structtypedef struct bitree ptr; / 指向根結(jié)點的指針 tasktype task; / 任務性質(zhì) elemtype;“遍歷二叉樹遍歷二叉樹”包括三項子任務:“遍歷左子樹”“遍歷右子樹”“訪問根結(jié)點”voidvoid inorder_iter( bitree bt ) / 利用棧實現(xiàn)中序遍歷二叉樹,t為指向二叉樹的根結(jié)點的頭指針 initstack(s); e.ptr=bt; e.task=travel; ifif(t) push(s, e); / 布置初始任務 whilewhile(! !stackempty(s) pop(s,e);
19、 if if (e.task=visit) visit(e.ptr); else else . . . . . /while /inorder_iterifif(! !e.ptr) / 處理非空樹的遍歷任務 p=e.ptr; e.ptr=p-rchild; push(s,e); / 最不迫切任務進棧 e.ptr=p; e.task=visit; push(s,e); e.ptr=p-lchild; e.task=travel; push(s,e); /if void inorder_i(bitree t, void (*visit) (telemtype& e) stack *s; t
20、 = gofarleft(t, s); / 找到最左下的結(jié)點 while(t) visit(t-data); if (t-rchild) else if ( !stackempty(s ) t = pop(s); / 退棧 else t = null; / ??毡砻鞅闅v結(jié)束 / while/ inorder_i t = gofarleft(t-rchild, s);bitnode *gofarleft(bitree t, stack *s) if (!t ) return null; while (t-lchild ) push(s, t); t = t-lchild; return t;中序
21、的非遞歸算法:void inorder(jd *bt) int i=0; jd *p,*sm; p=bt; do while(p!=null) si+=p; p=p-lchild; if(i0) p=s-i; printf(%dt,p-data); p=p-rchild; while(i0|p!=null); 非遞歸算法非遞歸算法abcdefgpip-a(1)abcdefgpip-ap-b(2)abcdefgpip-ap-bp-c(3)p=nullabcdefgip-ap-b訪問:訪問:c(4)pabcdefgip-a訪問:訪問:c b(5)abcdefgip-ap-d訪問:訪問:c bp(6
22、)abcdefgip-ap-dp-e訪問:訪問:c bp(7)abcdefgip-ap-d訪問:訪問:c b ep(8)abcdefgip-ap-dp-g訪問:訪問:c b ep=null(9)abcdefgip-a訪問:訪問:c b e g dp(11)abcdefgip-ap-f訪問:訪問:c b e g dp(12)abcdefgip-ap-d訪問:訪問:c b e gp(10)abcdefgip-a訪問:訪問:c b e g d fp=null(13)abcdefgi訪問:訪問:c b e g d f ap(14)abcdefgi訪問:訪問:c b e g d f ap=null(15
23、)層次遍歷 二叉樹的層次遍歷,是指從二叉樹的第二叉樹的層次遍歷,是指從二叉樹的第一層(根結(jié)點)開始,從上至下逐層遍一層(根結(jié)點)開始,從上至下逐層遍歷,在同一層中,則按從左到右的順序歷,在同一層中,則按從左到右的順序?qū)Y(jié)點逐個訪問。對結(jié)點逐個訪問。 按層次遍歷所得到的結(jié)果序列為:a b c d e f gabcdefg在進行層次遍歷時,可設(shè)置一個隊列結(jié)構(gòu),遍歷從二叉樹的根結(jié)點開始,首先將根結(jié)點指針入隊列,然后從隊頭取出一個元素,每取一個元素,執(zhí)行下面兩個操作:(1)訪問該元素所指結(jié)點;)訪問該元素所指結(jié)點;(2)若該元素所指結(jié)點的左、右孩子)若該元素所指結(jié)點的左、右孩子結(jié)點非空,則將該元素所指
24、結(jié)點的左結(jié)點非空,則將該元素所指結(jié)點的左孩子指針和右孩子指針順序入隊。孩子指針和右孩子指針順序入隊。void levelorder(bitree bt/ 層次遍歷二叉樹層次遍歷二叉樹btbitree queuemaxnode; int front,rear;if (bt=null) return;front = -1; rear=0;queuerear=bt;while(front!=rear) front+; visite(queuefront-data); /*訪訪問隊首結(jié)點的數(shù)據(jù)域問隊首結(jié)點的數(shù)據(jù)域*/ if (queuefront-rchild!=null) /* 將隊首結(jié)點的右孩結(jié)點
25、入隊將隊首結(jié)點的右孩結(jié)點入隊 */ rear+; queuerear = queuefront-rchild; if (queuefront-lchild!=null) /* 將隊首結(jié)點的左孩結(jié)點入隊將隊首結(jié)點的左孩結(jié)點入隊 */ rear+; queuerear = queuefront-lchild; 四四、遍歷算法的應用舉例遍歷算法的應用舉例2、統(tǒng)計二叉樹中葉子結(jié)點的個數(shù)、統(tǒng)計二叉樹中葉子結(jié)點的個數(shù)3、求二叉樹的深度、求二叉樹的深度(后序遍歷后序遍歷)4、復制二叉樹、復制二叉樹(后序遍歷后序遍歷)5 5、建立二叉樹的存儲結(jié)構(gòu)、建立二叉樹的存儲結(jié)構(gòu)1、查詢二叉樹中某個結(jié)點、查詢二叉樹中某個
26、結(jié)點1. 在二叉樹不空的前提下,和根結(jié)點的元素進行比較,若相等,則找到返回 true;2. 否則在左子樹中進行查找,若找到,則返回 true;3. 否則繼續(xù)在右子樹中進行查找,若找到,則返回 true,否則返回 false;status preorder (bitree t, elemtype x, bitree &p) / 若二叉樹中存在和若二叉樹中存在和 x 相同的元素,則相同的元素,則 p p 指向該結(jié)點并返回指向該結(jié)點并返回 ok,/ 否則返回否則返回 false if (t) if (t-data=x) p = t; return ok, /if else return fa
27、lse;else if (preorder(t-lchild, x, p) return ok; else return(preorder(t-rchild, x, p) ;/else2、統(tǒng)計二叉樹中葉子結(jié)點的個數(shù)、統(tǒng)計二叉樹中葉子結(jié)點的個數(shù)算法基本思想算法基本思想: : 先序(或中序或后序)遍歷二叉樹,在遍歷過程中查找葉子結(jié)點,并計數(shù)。由此,需在遍歷算法中增添一個需在遍歷算法中增添一個“計數(shù)計數(shù)”的參數(shù),的參數(shù),并將算法中“訪問結(jié)點” 的操作改為:若是葉子,則計數(shù)器增若是葉子,則計數(shù)器增1 1。void countleaf (bitree t, int& count) if ( t
28、) if (!t-lchild)& (!t-rchild) count+; / 對葉子結(jié)點計數(shù) countleaf( t-lchild, count); countleaf( t-rchild, count); / if / countleafint countleaf (bitree t)/返回指針t所指二叉樹中所有葉子結(jié)點個數(shù) if (!t ) return 0; if (!t-lchild & !t-rchild) return 1; else m = countleaf( t-lchild); n = countleaf( t-rchild); return (m+n)
29、; /else / countleafint count (bitree t)/返回指針t所指二叉樹中所有結(jié)點個數(shù) if (!t ) return 0; if (!t-lchild & !t-rchild) return 1; else m = count ( t-lchild); n = count ( t-rchild); return (m+n+1); /else / countleaf3、求二叉樹的深度、求二叉樹的深度(后序遍歷后序遍歷)算法基本思想算法基本思想: : 從二叉樹深度的定義可知,二叉樹的二叉樹的深度應為其左、右子樹深度的最大值加深度應為其左、右子樹深度的最大值加1
30、 1。由此,需先分別求得左、右子樹的深度,需先分別求得左、右子樹的深度,算法中“訪問結(jié)點”的操作為:求得左、求得左、右子樹深度的最大值,然后加右子樹深度的最大值,然后加 1 1 。 首先分析二叉樹的深度二叉樹的深度和它的左左、右子右子樹深度樹深度之間的關(guān)系。int depth (bitree t ) / 返回二叉樹的深度 if ( !t ) depthval = 0; else depthleft = depth( t-lchild ); depthright= depth( t-rchild ); depthval = 1 + (depthleft depthright ? depthlef
31、t : depthright); return depthval;void depth(bitree t , int level, int &dval) if ( t ) if (leveldval) dval = level; depth( t-lchild, level+1, dval ); depth( t-rchild, level+1, dval ); / 調(diào)用之前 level 的初值為 1。 / dval 的初值為 0.4、復制二叉樹、復制二叉樹其基本操作為其基本操作為: :生成一個結(jié)點。生成一個結(jié)點。根元素根元素t左子樹左子樹右子樹右子樹根元素根元素newt左子樹左子樹右
32、子樹右子樹左子樹左子樹右子樹右子樹(后序遍歷后序遍歷)bitnode *gettreenode(telemtype item, bitnode *lptr , bitnode *rptr ) if (!(t = new bitnode) exit(1); t- data = item; t- lchild = lptr; t- rchild = rptr; return t; 生成一個二叉樹的結(jié)點生成一個二叉樹的結(jié)點(其數(shù)據(jù)域為其數(shù)據(jù)域為item,左指針域為左指針域為lptr,右指針域為右指針域為rptr)bitnode *copytree(bitnode *t) if (!t ) retur
33、n null; if (t-lchild ) newlptr = copytree(t-lchild); /復制左子樹 else newlptr = null; if (t-rchild ) newrptr = copytree(t-rchild); /復制右子樹 else newrptr = null; newt = gettreenode(t-data, newlptr, newrptr); return newt; / copytreeabcdefghk d c h k g a例如例如: :下列二叉樹下列二叉樹的復制過程如下的復制過程如下: :newt f b e 5 5、建立二叉樹的存
34、儲、建立二叉樹的存儲結(jié)構(gòu)結(jié)構(gòu)不同的定義方法相應有不同的不同的定義方法相應有不同的存儲結(jié)構(gòu)的建立算法存儲結(jié)構(gòu)的建立算法 以字符串的形式以字符串的形式 “根根 左子樹左子樹 右子樹右子樹”定義一棵二叉樹定義一棵二叉樹例如例如: :以空白字符“ ”表示abcda(b( ,c( , ),d( , )空樹空樹只含一個根結(jié)點只含一個根結(jié)點的二叉樹的二叉樹a以字符串“a ”表示以下列字符串表示status createbitree(bitree &t) scanf(&ch); if (ch= ) t = null; else if (!(t = new bitnode) exit(overf
35、low); t-data = ch; / 生成根結(jié)點 createbitree(t-lchild); / 構(gòu)造左子樹 createbitree(t-rchild); / 構(gòu)造右子樹 return ok; / createbitreea b c d a bcd上頁算法執(zhí)行過程舉例如下:atbcdscanf(&ch);if (ch= ) t = null;else if (!(t = new bitnode) exit(overflow); t-data = ch;createbitree(t-lchild); createbitree(t-rchild); 按給定的表達式建相應二叉樹按給
36、定的表達式建相應二叉樹 由先綴表示式建樹由先綴表示式建樹例如:已知表達式的先綴表示式 - -+ + a b c / d e 由原表達式建樹由原表達式建樹例如:已知表達式 (a+b)c d/e d/e對應先綴表達式 - -+ + a b c / d e的二叉樹的二叉樹abcde- -+/特點特點: 操作數(shù)為葉子葉子結(jié)點, 運算符為分支分支結(jié)點scanf(&ch);if ( in(ch, 字母集 ) 建葉子結(jié)點;else 建根結(jié)點; 遞歸建左子樹; 遞歸建右子樹;由先綴表示式建樹的算法的基本操作:由先綴表示式建樹的算法的基本操作:a+b(a+b)c d/e d/ea+bc 分析表達式和二叉
37、樹的關(guān)系分析表達式和二叉樹的關(guān)系:abbac+abc(a+b)c/deabc+- -基本操作基本操作:scanf(&ch);if (in(ch, 字母集 ) 建葉子結(jié)點; 暫存; else if (in(ch, 運算符集) 和前一個運算符比較優(yōu)先數(shù); 若當前的優(yōu)先數(shù)“高”,則暫存; 否則建子樹;void crtexptree(bitree &t, char exp ) initstack(s); push(s, #); initstack(ptr); p = exp; ch = *p; while (!(gettop(s)=# & ch=#) if (!in(ch, o
38、p) crtnode( t, ch ); / 建葉子結(jié)點并入棧 else if ( ch!= # ) p+; ch = *p; / while pop(ptr, t); / crtexptree switch (ch) case ( : push(s, ch); break; case ) : pop(s, c); while (c!= ( ) crtsubtree( t, c); / 建二叉樹并入棧建二叉樹并入棧 pop(s, c) break; defult : / switch while(!gettop(s, c) & ( precede(c,ch) crtsubtree( t
39、, c); pop(s, c);if ( ch!= # ) push( s, ch); break;建葉子結(jié)點的算法為:void crtnode(bitree& t,char ch) if (!(t= new bitnode) exit(overflow); t-data = char; t-lchild = t-rchild = null; push( ptr, t );建子樹的算法為:void crtsubtree (bitree& t, char c) if (!(t= new bitnode) exit(overflow); t-data = c; pop(ptr, r
40、c); t-rchild = rc; pop(ptr, lc); t-lchild = lc; push(ptr, t); 僅知二叉樹的先序序列“abcdefg” 不能唯一確定一棵二叉樹,由二叉樹的先序和中序序列建樹由二叉樹的先序和中序序列建樹 如果同時已知二叉樹的中序序列“cbdaegf”,則會如何? 二叉樹的先序序列二叉樹的中序序列左子樹左子樹左子樹左子樹 右子樹右子樹右子樹右子樹根根根根a b c d e f gc b d a e g f例如例如: :aab bccddeeffggabcdefg先序序列中序序列void crtbt(bitree& t, char pre, cha
41、r 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; else / / crtbt if (!(t= new bitnode) exit(overflow);t-data = preps;if (k=is) t-lchild = null;else crtbt(t-lchild, pre, ino, p
42、s+1, is, k-is );if (k=is+n-1) t-rchild = null;else crtbt(t-rchild, pre, ino, ps+1+(k-is), k+1, n-(k-is)-1 ); 6.4 樹和森林樹和森林 的表示方法的表示方法樹的三種存儲結(jié)構(gòu)樹的三種存儲結(jié)構(gòu)一、一、雙親表示法雙親表示法二、二、孩子鏈表表示法孩子鏈表表示法三、三、樹的二叉鏈表樹的二叉鏈表( (孩子孩子- -兄弟)兄弟) 存儲表示法存儲表示法abcdefgr=0n=60 a -11 b 02 c 03 d 04 e 2 5 f 26 g 5data parent一、雙親表示法一、雙親表示法:
43、typedef struct ptnode elem data; int parent; / 雙親位置域 ptnode; data parent#define max_tree_size 100結(jié)點結(jié)構(gòu)結(jié)點結(jié)構(gòu):c語言的類型描述語言的類型描述: :typedef struct ptnode nodesmax_tree_size; int r, n; / 根結(jié)點的位置和結(jié)點個數(shù) ptree;樹結(jié)構(gòu)樹結(jié)構(gòu):二、孩子鏈表表示法二、孩子鏈表表示法: : 多重鏈表:每個結(jié)點有多個指針域,分多重鏈表:每個結(jié)點有多個指針域,分別指向其子樹的根別指向其子樹的根l結(jié)點同構(gòu):結(jié)點的指針個數(shù)相等,為結(jié)點同構(gòu):結(jié)點的
44、指針個數(shù)相等,為樹的度樹的度d dl結(jié)點不同構(gòu):結(jié)點指針個數(shù)不等,為結(jié)點不同構(gòu):結(jié)點指針個數(shù)不等,為該結(jié)點的度該結(jié)點的度d ddata child1 child2 . childddata degree child1 child2 . childdr=0n=6 dataabcdefg0 a -11 b 02 c 03 d 04 e 25 f 26 g 464 5 1 2 3二、孩子鏈表表示法二、孩子鏈表表示法:-1 0 0 0 2 2 4firstchildparenttypedef struct ctnode int child; struct ctnode *nextchild; *chi
45、ldptr;孩子結(jié)點結(jié)構(gòu)孩子結(jié)點結(jié)構(gòu): child nextchildc語言的類型描述語言的類型描述: : typedef struct elem data; childptr firstchild; / 孩子鏈的頭指針 ctbox;雙親結(jié)點結(jié)構(gòu)雙親結(jié)點結(jié)構(gòu) data firstchildtypedef struct ctbox nodesmax_tree_size; int n, r; / 結(jié)點數(shù)和根結(jié)點的位置 ctree;樹結(jié)構(gòu)樹結(jié)構(gòu):abcdefgroot ab c e d f g ab c e d f g 三、樹的二叉鏈表三、樹的二叉鏈表 (孩子孩子-兄弟)存儲表示法兄弟)存儲表示法r
46、oottypedef struct csnode elem data; struct csnode *firstchild, *nextsibling; csnode, *cstree;c語言的類型描述語言的類型描述: :結(jié)點結(jié)構(gòu)結(jié)點結(jié)構(gòu): firstchild data nextsibling將一棵樹轉(zhuǎn)換為二叉樹的方法是:(1)樹中所有相鄰兄弟之間加一條連線。(2)對樹中的每個結(jié)點,只保留它與第一個孩子結(jié)點之間的連線,刪去它與其它孩子結(jié)點之間的連線。(3)以樹的根結(jié)點為軸心,將整棵樹順時針轉(zhuǎn)動一定的角度,使之結(jié)構(gòu)層次分明。63 二叉樹與樹、森林之間的轉(zhuǎn)換二叉樹與樹、森林之間的轉(zhuǎn)換631 樹轉(zhuǎn)
47、換為二叉樹樹轉(zhuǎn)換為二叉樹632 森林轉(zhuǎn)換為二叉樹 森林轉(zhuǎn)換為二叉樹的方法如下:(1)將森林中的每棵樹轉(zhuǎn)換成相應的二叉樹(2)第一棵二叉樹不動,從第二棵二叉樹開始,依次把后一棵二叉樹的根結(jié)點作為前一棵二叉樹根結(jié)點的右孩子,當所有二叉樹連起來后,此時所得到的二叉樹就是由森林轉(zhuǎn)換得到的二叉樹。633 二叉樹轉(zhuǎn)換為樹和森林二叉樹轉(zhuǎn)換為樹和森林 (1 1)若某結(jié)點是其雙親的左孩子,)若某結(jié)點是其雙親的左孩子,則把該結(jié)點的右孩子、右孩子的右則把該結(jié)點的右孩子、右孩子的右孩子,都與該結(jié)點的雙親結(jié)點用線孩子,都與該結(jié)點的雙親結(jié)點用線連起來;連起來; (2 2)刪去原二叉樹中所有的雙親結(jié))刪去原二叉樹中所有的雙
48、親結(jié)點與右孩子結(jié)點的連線;點與右孩子結(jié)點的連線; 由此,樹和森林的各種操作均可與二叉樹的各種操作相對應。 應當注意的是,應當注意的是,和樹對應的二叉樹,其左、右子樹的概念已改變?yōu)椋?左是孩子,右是兄弟左是孩子,右是兄弟6.4 哈哈 夫夫 曼曼 樹樹 與與 哈哈 夫夫 曼曼 編編 碼碼 最優(yōu)樹的定義最優(yōu)樹的定義 如何構(gòu)造最優(yōu)樹如何構(gòu)造最優(yōu)樹 前綴編碼前綴編碼 一、最優(yōu)樹的定義一、最優(yōu)樹的定義樹的路徑長度樹的路徑長度定義為: 樹中每個結(jié)點的路徑長度之和。 結(jié)點的路徑長度結(jié)點的路徑長度定義為: 從根結(jié)點到該結(jié)點的路徑上 分支的數(shù)目。 樹的帶權(quán)路徑長度樹的帶權(quán)路徑長度定義為: 樹中所有葉子結(jié)點的帶權(quán)路
49、徑長度結(jié)點的帶權(quán)路徑長度之和 wpl(t) = wklk (對所有葉子結(jié)點) 在所有含 n 個葉子結(jié)點、并帶相同權(quán)值的 m 叉樹中,必存在一棵其帶權(quán)路徑帶權(quán)路徑長度取最小值長度取最小值的樹,稱為“最優(yōu)樹最優(yōu)樹”。例如:例如:27 9 75492wpl(t)= 72+52+23+43+92 =60wpl(t)= 74+94+53+42+21 =89 54根據(jù)給定的 n 個權(quán)值 w1, w2, , wn構(gòu)造 n 棵二叉樹的集合 f = t1, t2, , tn,其中每棵二叉樹中均只含一個帶權(quán)值 為 wi 的根結(jié)點,其左、右子樹為空樹;二、如何構(gòu)造最優(yōu)樹二、如何構(gòu)造最優(yōu)樹(1)(赫夫曼算法) 以二叉
50、樹為例: 在 f 中選取其根結(jié)點的權(quán)值為最 小的兩棵二叉樹,分別作為左、 右子樹構(gòu)造一棵新的二叉樹,并 置這棵新的二叉樹根結(jié)點的權(quán)值 為其左、右子樹根結(jié)點的權(quán)值之 和;(2) 從f中刪去這兩棵樹,同時加入 剛生成的新樹; 重復 (2) 和 (3) 兩步,直至 f 中只 含一棵樹為止。(3)(4)9例如: 已知權(quán)值 w= 5, 6, 2, 9, 7 562752769767139527671395279527166713292.哈夫曼樹的造構(gòu)造算法哈夫曼樹的造構(gòu)造算法根據(jù)二叉樹的性質(zhì)可知,具有n個葉子結(jié)點的哈夫曼樹共有2n1個結(jié)點,所以數(shù)組huffnode的大小設(shè)置為2n1weightlchil
51、drchildparent下面給出哈夫曼樹的構(gòu)造算法。#define maxvalue 10000 /* 定義最大權(quán)值 */#define maxleaf 30 /*定義哈夫曼樹中葉子結(jié)點個數(shù)*/#define maxnode maxleaf*2-1typedef struct int weight; int parent; int lchild,rchild;hnodetype;for (i=0;i2*n-1;i+) /* 數(shù)組huffnode 初始化 */ huffnodei.weight=0; huffnodei.parent=-1; huffnodei.lchild=-1; huffn
52、odei.rchild=-1; for (i=0;in;i+) scanf(“%d”,&huffnodei.weight); /* 將找出的兩棵子樹合并為一棵子樹將找出的兩棵子樹合并為一棵子樹 */ huffnodex1.parent=n+i; huffnodex2.parent=n+i; huffnoden+i.weight= huffnodex1.weight+huffnodex2.weight; huffnoden+i.lchild=x1; huffnoden+i.rchild=x2; for (i=0;in-1;i+) m1=m2=maxvalue; x1=x2=0; for
53、(j=0;jn+i;j+) if (huffnodej.weightm1 & huffnodej.parent=-1) m2=m1; x2=x1; m1=huffnodej.weight; x1=j; else if (huffnodej.weightfirstchild);d2 = depth(t-nextsibling);return maxd1+1,d2int treedepth( ctree t ) / t 是樹的孩子鏈表存儲結(jié)構(gòu), / 返回該樹的深度 if ( t.n = 0) return 0; else return depth( t, t.r ); / treedept
54、h一、求樹的深度的算法:一、求樹的深度的算法:int depth( ctree t, int root ) max = 0; p = t.nodesroot.firstchild; while ( p ) h = depth( t, p-child ); if ( h max ) max = h; p = p-nextchild; /while return max+1;二、二、輸出樹中所有從根到葉子的路徑的算法輸出樹中所有從根到葉子的路徑的算法: a b c de f g h i j k例如:對左圖所示的樹,其輸出結(jié)果應為:a b ea b fa ca d g h ia d g h ja d
55、 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é)點的路徑輸出二叉樹上從根到所有葉子結(jié)點的路徑void outpath( bitree t, stack& s ) while ( !t ) push(s, t-data
56、 ); if ( !t-firstchild ) printstack(s); else outpath( t-firstchild, s ); pop(s); t = t-nextsibling; / while / outpath/ 輸出森林中所有從根到葉的路徑三、建樹的存儲結(jié)構(gòu)的算法三、建樹的存儲結(jié)構(gòu)的算法: 和二叉樹類似,不同的定義相應有不同的算法。 假設(shè)以二元組(f,c)的形式自上而下自上而下、自左而右自左而右依次輸入樹的各邊,建立樹的孩子孩子-兄弟鏈表兄弟鏈表。abcdefg例如例如:對下列所示樹的輸入序列應為:(#, a)(a, b)(a, c)(a, d)(c, e)(c, f
57、)(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(q,s); / 取
58、隊列頭元素(指針值)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é)點 本章作業(yè)本章作業(yè) 6.33, 6.34, 6.43, 6.45 6.47, 6.51, 6.56 6.59, 6.61, 6.63, 6.686.5線索二叉樹線索二叉樹 何謂線索二叉樹?何謂線索二叉樹? 線索鏈表的遍歷算法線索鏈表的遍歷算法 如何建立線索鏈表?如何建
59、立線索鏈表?一、一、何謂線索二叉樹?何謂線索二叉樹?遍歷二叉樹的結(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ū)”和 “后繼” 的指針指針,稱作“線線索索”與其相應的二叉樹,稱作 “線索二叉樹線索二叉樹”包含 “線索” 的存儲結(jié)構(gòu),稱作 “線索鏈線索鏈表表”a b c d e f g h k d c b e 對對線索鏈表線索鏈表中結(jié)點的約定:中結(jié)點的約定: 在二叉鏈表的結(jié)點中增加兩個標志域增加兩個標志域,并作如下規(guī)定:若該結(jié)點的左子樹不空,若該結(jié)點的左子樹不空,則lchild域的指針指向其左子樹, 且左標志域的值為“指針 link”; 否則,lchild域的指針指向其“前驅(qū)”, 且左標志的值為“線索 thread” 。若該結(jié)點的右子樹不空,若該結(jié)點的右子樹不空,則rchild域的指針
溫馨提示
- 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. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度鍋爐節(jié)能技術(shù)改造咨詢合同范本
- 2025年度新型建筑工程承包合同范本
- 2025年度汽車后市場廣告設(shè)計制作委托代理合同
- 2025年度空場地租賃合同(含租賃期滿資產(chǎn)處置協(xié)議)
- 2025年度高端醫(yī)療設(shè)備租賃合同范本-@-1
- 2025年度凱悅酒店消防設(shè)備維保與更換合同
- 網(wǎng)絡建設(shè)施工合同
- 2024車輛轉(zhuǎn)讓合同常用范本
- 2025年物業(yè)供氣供熱合同
- 2025年分期購買廚房電子器具合同
- 山東省濟寧市2025屆高三歷史一輪復習高考仿真試卷 含答案
- 五年級數(shù)學(小數(shù)乘法)計算題專項練習及答案
- 交通法規(guī)教育課件
- 產(chǎn)前診斷室護理工作總結(jié)
- 6S管理知識培訓課件
- 醫(yī)院培訓課件:《猴痘流行病學特點及中國大陸首例猴痘病例調(diào)查處置》
- 氫氣-安全技術(shù)說明書MSDS
- 產(chǎn)科護士臨床思維能力培養(yǎng)
- 開曼群島公司法2024版中文譯本(含2024年修訂主要內(nèi)容)
- 市政工程人員績效考核制度
- 公園景區(qū)安全生產(chǎn)
評論
0/150
提交評論