樹:是n(n>=0)個節(jié)點的有限集,n=0時稱為空樹。在任何一棵非空樹中:1 有且僅有一個特定的稱為根(root)的節(jié)點; 2 n>1時,其余節(jié)點可分為m(m>0)個互不相交的優(yōu)先集,其中每一個集合又是一棵樹,稱為根的子樹。(n>0時根節(jié)點唯一,m>0時,子樹個數(shù)沒有限制,但他們一定互不相交)。
- 結(jié)點擁有的子樹數(shù)稱為結(jié)點的度(Degree)
- 度為零的結(jié)點稱為葉結(jié)點(Leaf)或終端結(jié)點
- 度不為零的結(jié)點稱為 分支結(jié)點 或 非終端結(jié)點,除根結(jié)點外,分支結(jié)點也稱為內(nèi)部結(jié)點
- 各結(jié)點度的最大值稱為 樹的度
- 結(jié)點的層次(Level)從根開始定義起,根為第一層,孩子以此類推,雙親在同一層的結(jié)點互為堂兄弟
- 樹中結(jié)點的最大層次稱為樹的深度(Depth)或高度
線性結(jié)構(gòu)/樹結(jié)構(gòu) 對比
線性結(jié)構(gòu)
第一個數(shù)據(jù)元素:無前驅(qū)
最后一個數(shù)據(jù)元素:無后驅(qū)
中間元素:一個前驅(qū)一個后驅(qū)
樹結(jié)構(gòu)
根結(jié)點:無雙親,唯一
葉結(jié)點: 無孩子
中間結(jié)點:一個雙親多個孩子
樹的表示法
- 雙親表示法:每個結(jié)點附設(shè)一個指針指向雙親結(jié)點的位置
- 孩子表示法:每個結(jié)點設(shè)置多個指針,每個指針指向一棵子樹的根結(jié)點,這種方法也叫多重鏈表表示法
- 孩子兄弟表示法:每個結(jié)點設(shè)置兩個指針,分別指向該結(jié)點的第一個孩子和此結(jié)點的右兄弟
二叉樹 可以為空,稱為空二叉樹,或者由一個根結(jié)點和兩棵互不相交的,分別稱為根結(jié)點的左子樹和右子樹的二叉樹組成
二叉樹的特點:
- 不存在度大于2的結(jié)點
- 左右子樹有序
二叉樹的性質(zhì):
- 性質(zhì)1:在二叉樹的第i層至多有2^(i-1)個節(jié)點(i>=1)。
- 性質(zhì)2:深度為k的二叉樹至多有2^k - 1個節(jié)點。
- 性質(zhì)3:二叉樹中,終點節(jié)點(度為0)個數(shù)n0與度為2的節(jié)點個數(shù)n2關(guān)系:n0 = n2 + 1。
分析:二叉樹中節(jié)點的度可以是0,1, 2。也就是說需要證明度為0的節(jié)點和度為2的節(jié)點的關(guān)系不變。
證明:
設(shè)二叉樹中,度為i的節(jié)點表示成ni。
則二叉樹總的節(jié)點數(shù)n = n0 + n1 + n2。
因為除根節(jié)點外,每一個節(jié)點都是另一個節(jié)點的孩子,所以孩子數(shù)為n - 1。
度為i(i = 1, 2, 3)的節(jié)點,有i個孩子,孩子數(shù) n - 1 = n0 × 0 + n1 × 1 + n2 × 2 = 2 × n2 + n1。
所以n0 + n1 + n2 - 1 = 2 × n2 + n1 => n2 = n0 - 1 => n0 = n2 + 1。 - 節(jié)點樹為n的完全二叉樹,根據(jù):
2^(n - 1) - 1 < n <= 2^n - 1
,可知深度為log(2)(n) <向下取整> + 1 - 在按層編號的n個結(jié)點的完全二叉樹中,任意一個結(jié)點i(1 <= i <= n)有:
1). i = 1時,結(jié)點i是樹的根,i > 1時,結(jié)點i的雙親為i/2(向下取整)。
2). 2 × i > n時,結(jié)點i無左孩子,為葉結(jié)點,否則結(jié)點i的左孩子為2i。
3). 2 × i + 1 > n時,結(jié)點i無右孩子,否則結(jié)點i的右孩子為2i + 1。
; 即把樹按層映射到數(shù)組中,如果數(shù)組以0為起點,可以按照`性質(zhì)5`求出結(jié)點i的父結(jié)點,左孩子結(jié)點,右孩子結(jié)點。
(defun parent (i)
(if (= i 0)
0
(floor (/ (- i 1) 2))))
(defun left (i)
(+ (* 2 i) 1))
(defun right (i)
(* 2 (+ i 1)))
特殊二叉樹:
- 左(右)斜樹:所有結(jié)點都只有左(右)子樹的二叉樹
- 滿二叉樹:所有分支結(jié)點都存在左右子樹,并且所有的葉子都在同一層上的二叉樹,即當(dāng)深度為k時,結(jié)點必須為2^k - 1個。
- 完全二叉樹:如果具有n個結(jié)點的二叉樹按層序編號,如果編號為i(1<= i <=n)的結(jié)點與同樣深度的滿二叉樹中編號為i的結(jié)點在二叉樹中位置完全相同,則為完全二叉樹
二叉樹的遍歷:
定義數(shù)的結(jié)構(gòu)為:
tree {
l-child,
r-child
}
- 前序遍歷: 若二叉樹為空, 則空操作返回, 否則先訪問根結(jié)點, 然后前序遍歷左子樹, 再前序遍歷右子樹.
preorder (tree tr) {
if (tr) {
visit(tr)
preorder(tr -> l-child)
preorder(tr -> r-child)
}
}
- 中序遍歷: 若二叉樹為空, 則空操作返回, 否則從根結(jié)點開始, 中序遍歷根結(jié)點的左子樹, 然后訪問根結(jié)點, 最后中序遍歷右子樹.
inorder (tree tr) {
if (tr) {
inorder(tr -> l-child)
visit(tr)
inorder(tr -> r-child)
}
}
- 后序遍歷: 若二叉樹為空, 則空操作返回, 否則從左到右先葉子后結(jié)點的方式遍歷訪問左右子樹, 最后訪問根結(jié)點.
postorder (tree tr) {
if (tr) {
postorder(tr -> l-child)
postorder(tr -> r-child)
visit(tr)
}
}
- 層序遍歷: 若二叉樹為空, 則空操作返回, 否則從樹的第一層, 從上而下逐層遍歷, 在同一層中, 按從左到右的順序?qū)Y(jié)點逐個訪問.
線索二叉樹(Threaded Binary Tree)
- 指向前驅(qū)或后繼的指針稱為線索, 加上線索的二叉樹表稱為線索鏈表, 也就是線索二叉樹.
- 對二叉樹以某種次序遍歷使其變?yōu)榫€索二叉樹的過程稱作是線索化.
樹轉(zhuǎn)為二叉樹
- 加線, 在所有兄弟結(jié)點之間加一條連線.
- 去線, 對樹中每個結(jié)點, 只保留它與第一個孩子結(jié)點的連線, 刪除它與其它孩子結(jié)點的連線.
- 層次調(diào)整, 以樹的根節(jié)點為軸心, 將整棵樹順時針旋轉(zhuǎn)一定角度, 使之結(jié)構(gòu)層次分明. 注意: 第一個孩子是二叉樹的左孩子, 兄弟轉(zhuǎn)換過來的孩子是結(jié)點的右孩子.