树——树和二叉树
樹和二叉樹
- 樹
- 樹的定義
- 樹的存儲結(jié)構(gòu)
- 雙親表示法
- 孩子鏈表
- 孩子兄弟表示法
- 二叉樹
- 定義
- 案例引入
- 樹與二叉樹的抽象數(shù)據(jù)類型定義
- 二叉樹的性質(zhì)
- 存儲結(jié)構(gòu)
- 二叉樹的順序存儲
- 二叉樹的鏈式存儲*
- 遍歷二叉樹方法
- 先序遍歷法
- 中序遍歷
- 后序遍歷
- 層次遍歷
- 根據(jù)遍歷序列確定二叉樹
- 遞歸調(diào)用的步驟
- 二叉樹遍歷算法的應(yīng)用
- 二叉樹的建立
- 二叉樹的復(fù)制
- 二叉樹的深度
- 二叉樹結(jié)點總數(shù)
- 二叉樹葉子結(jié)點數(shù)
- 線索二叉樹
樹
樹的定義
- 樹形結(jié)構(gòu)(非線性結(jié)構(gòu)):結(jié)點之間有分支;具有層次結(jié)構(gòu)
- 例子:(1)自然界:樹;(2)人類社會:家譜、行政組織機構(gòu);(3)計算機領(lǐng)域:①編譯:用樹表示源程序的語法結(jié)構(gòu) ②數(shù)據(jù)庫系統(tǒng):用樹組織信息;③算法分析:用樹描述執(zhí)行過程
- 樹是n個結(jié)點的有限集,樹的定義顯然是遞歸結(jié)構(gòu)
- 樹的其他表示方式
- 樹的基本術(shù)語
(1)結(jié)點:數(shù)據(jù)元素以及指向子樹的分支
(2)根結(jié)點:非空樹中無前驅(qū)結(jié)點的結(jié)點
(3)結(jié)點的度:結(jié)點擁有的子樹數(shù)
(4)樹的度:樹內(nèi)各結(jié)點的度的最大值
(5)葉子結(jié)點:終端結(jié)點,度=0
(6)分支結(jié)點:非終端結(jié)點,度≠0
(7)內(nèi)部結(jié)點:根結(jié)點以外的分支結(jié)點
(8)孩子、雙親:結(jié)點的子樹的根稱為該結(jié)點的孩子,該結(jié)點稱為孩子的雙親
(9)兄弟、堂兄弟
(10)祖先:從根到該結(jié)點所經(jīng)分支上的所有結(jié)點
(11)子孫:以某結(jié)點為根的子樹中的任一結(jié)點
(12)樹的深度(高度):樹中結(jié)點的最大層次,根結(jié)點到最底層的最短路徑
(13)有序樹:樹中結(jié)點的各子樹從左至右有次序(最左邊的為第一個孩子
(14)無序樹:樹中結(jié)點的各子樹無次序
(15)森林:是m(m≥0)棵互不相交的樹的集合
把根節(jié)點刪除的樹就成了森林
一棵樹可以看成是一個特殊的森林;給森林中的各子樹加上一個雙親結(jié)點,森林就變成了樹
因此,樹一定是森林,森林不一定是樹
樹的存儲結(jié)構(gòu)
雙親表示法
實現(xiàn):定義結(jié)構(gòu)數(shù)組;存放樹的結(jié)點,每個結(jié)點含兩個域:
- 數(shù)據(jù)域:存放結(jié)點本身的信息
- 雙親域:指示本結(jié)點的雙親結(jié)點數(shù)組中的位置
特點:找雙親容易,找孩子難
孩子鏈表
孩子兄弟表示法
又叫二叉樹表示法/二叉鏈表表示法
實現(xiàn):用二叉鏈表作樹的存儲結(jié)構(gòu),鏈表中每個結(jié)點的兩個指針域分別指向其第一個孩子結(jié)點和下一個兄弟結(jié)點
typedef struct CSNode {
ElemType data;
struct CSNode *firstchild, *nextsibling;
}CSNode, *CSTree;
二叉樹
定義
二叉樹的結(jié)構(gòu)最簡單,規(guī)律性最強;可以證明,所有的樹都能轉(zhuǎn)為唯一對應(yīng)的二叉樹,不失一般性
普通樹若不轉(zhuǎn)化為二叉樹,運算很難實現(xiàn)
(1)每個結(jié)點最多有倆孩子(二叉樹中不存在度大于2的結(jié)點)
(2)子樹有左右之分,次序不能顛倒
(3)二叉樹可以是空集合,根可以有空的左子樹或空的右子樹
二叉樹也并非有序樹,而是一種獨立的概念
雖然二叉樹與樹的概念不同,但是有關(guān)樹的基本術(shù)語對二叉樹都適用
案例引入
將數(shù)據(jù)文件轉(zhuǎn)換為由0、1組成的二進制串,稱之為編碼
樹與二叉樹的抽象數(shù)據(jù)類型定義
相似,因此主要研究二叉樹的抽象數(shù)據(jù)類型定義
CreateBiTree(&T,definition) //初始條件:definition給出二叉樹T的定義 操作結(jié)果:按definition構(gòu)造二叉樹
PreOrderTraverse(T) //初始條件:二叉樹T存在 操作結(jié)果:先序遍歷T,對每個結(jié)點訪問一次
InOrderTraverse(T) //初始條件:二叉樹T存在 操作結(jié)果:中序遍歷T,對每個結(jié)點訪問一次
PostOrderTraverse(T) //初始條件:二叉樹T存在 操作結(jié)果:后序遍歷T,對每個結(jié)點訪問一次
二叉樹的性質(zhì)
滿二叉樹:一棵深度為k且有2^k-1個結(jié)點的二叉樹稱為滿二叉樹
特點:①每一層上的結(jié)點數(shù)都是最大結(jié)點數(shù)(每層都滿)②葉子結(jié)點全部在最底層
編號:①規(guī)則:從根結(jié)點開始,自上而下,自左而右 ②每一結(jié)點的位置都有元素
完全二叉樹:
注意:在滿二叉樹中,從最后一個節(jié)點開始,連續(xù)去掉任意個結(jié)點,即是一棵完全二叉樹
特點:①葉子只可能分布在層次最大的兩層上 ②對任一結(jié)點,如果其右子樹的最大層次為i,則其左子樹的最大層次必為i或i+1
滿二叉樹一定是完全二叉樹,完全二叉樹不一定是滿二叉樹
性質(zhì):
證明:邊數(shù)m = 結(jié)點n - 1(每個結(jié)點與雙親結(jié)點有一條邊,除了根結(jié)點)//邊數(shù)m = 2n2+n11(度為2的n2產(chǎn)生2條邊,度為1的n1產(chǎn)生1條邊)
∴n-1 = 2n2+1n1 ,又∵n = n0+n1+n2 ∴n0 = n2+1
存儲結(jié)構(gòu)
順序存儲結(jié)構(gòu)+鏈式存儲結(jié)構(gòu)(二叉鏈表+三叉鏈表)
二叉樹的順序存儲
實現(xiàn):按滿二叉樹的結(jié)點層次編號,依次存放二叉樹中的數(shù)據(jù)元素
SqBiTree bt; //定義了bt數(shù)組
二叉樹的鏈式存儲*
typedef struct BiNode {
TElemType data;
struct BiNode * lchild, *rchild; //左右孩子指針
}BiNode, *BiTree;
typedef struct TriTNode {
TElemType data;
struct TriTNode *lchild,*rchid,*parent;
}
遍歷二叉樹方法
由上可知,遍歷時用遞歸操作
先序遍歷法
若二叉樹為空,則空操作;
否則:
(1)訪問根節(jié)點
(2)先序遍歷左子樹
(3)先序遍歷右子樹
- 先序遍歷:ABELADHMIJ
遞歸算法
非遞歸算法
思路:
中序遍歷
若二叉樹為空,則空操作;
否則:
(1)中序遍歷左子樹
(2)訪問根節(jié)點
(3)中序遍歷右子樹
- 中序遍歷:ELBAMHIDJ
遞歸算法
非遞歸算法
關(guān)鍵:在中序遍歷過某結(jié)點的整個左子樹后,如何找到該結(jié)點的根以及右子樹
基本思想:
后序遍歷
若二叉樹為空,則空操作;
否則:
(1)后序遍歷左子樹
(2)后序遍歷右子樹
(3)訪問根節(jié)點
- 后序遍歷:LEBMIHJDA
遞歸算法:
其中先序的結(jié)果叫做前綴表示(波蘭式)
中序的結(jié)果叫做中綴表示
后序的結(jié)果叫做后綴表示(逆波蘭式)
層次遍歷
對于一棵二叉樹,從根結(jié)點開始,從上到下,從左到右的順序訪問每一個結(jié)點,每個結(jié)點僅僅訪問一次
算法設(shè)計思路:使用一個隊列
Ⅰ將根結(jié)點進隊
Ⅱ隊不空時循環(huán):從隊列中出列一個結(jié)點*p,訪問它;
①若它有左孩子結(jié)點,將左孩子結(jié)點進隊
②若它有右孩子結(jié)點,將右孩子結(jié)點進隊
根據(jù)遍歷序列確定二叉樹
- 先序序列和中序序列
eg:
先序:ABCDEFGHIJ
中序:CDBFEAIHGJ - 后序:DCFEBIHJGA
- 中序序列和后序序列
eg:
中序:BDCEAFHG
后序:DECBHGFA - 先序:ABCDEFGH
遞歸調(diào)用的步驟
時間效率:O(n) //每個結(jié)點只訪問一次
空間效率:O(n) //棧占用的最大輔助空間
二叉樹遍歷算法的應(yīng)用
二叉樹的建立
僅輸入ABCDEGF所得的樹不唯一
對如圖所示的二叉樹,輸入字符:ABC##DE#G##F###,僅得到左邊的樹
二叉樹的復(fù)制
如果是空樹,遞歸結(jié)束
否則,申請新結(jié)點空間,復(fù)制根結(jié)點
- 遞歸復(fù)制左子樹
- 遞歸復(fù)制右子樹
二叉樹的深度
如果是空樹,則深度為0
否則,遞歸計算左子樹的深度記為m,遞歸計算右子樹的深度記為n,二叉樹的深度則為m與n的較大者+1
二叉樹結(jié)點總數(shù)
如果是空樹,則結(jié)點個數(shù)為0;
否則,結(jié)點個數(shù) = 左子樹的結(jié)點個數(shù) + 右子樹的結(jié)點個數(shù) + 1
二叉樹葉子結(jié)點數(shù)
如果是空樹,則葉子結(jié)點個數(shù)為0
否則,為左子樹的葉子結(jié)點個數(shù)+右子樹的葉子結(jié)點個數(shù)
注:葉子結(jié)點:左子樹和右子樹均為空
線索二叉樹
如果某個結(jié)點的左孩子為空,則將空的左孩子指針域改為指向其前驅(qū);如果某個結(jié)點的右孩子為空,則將空的右孩子指針域指向其后繼,這種改變指向的指針稱為“線索”
加上了線索的二叉樹稱為線索二叉樹
對二叉樹按某種遍歷次序使其變?yōu)榫€索二叉樹的過程叫線索化
定義:
typedef struct BiThrNode {
int data;
int ltag, rtag;
struct BiThrNode *lchild, *rachild;
}BiThrNode, *BiThrTree;
eg:
改進
總結(jié)
- 上一篇: 模板代码
- 下一篇: SMARTFORM 插入列、增加表格边框