二叉樹
二叉樹(Binary Tree)是樹的一種特殊形式,也就是每個節點之下最多擁有2個孩子,相應地若最多不超過M個孩子,那就成爲M叉樹,但實際上我們統稱爲多叉樹。對於二叉樹,常用的定理有四條:
- 深度爲i的二叉樹最多含有
2i−1 個節點; - 第i層至多有
2i−1 個節點; 對於任意一顆二叉樹,若其終端節點數爲
n0 ,度爲2的節點數爲n2 ,則n0=n2+1 。證明如下:(1)n=n0+n1+n2
(2)n=B+1(B爲分支總數)
(3)B=n1+2n2
由上述三式即可得出此定理。對於一棵完全二叉樹(除最後一層外每一層都爲滿二叉樹)而言,其葉子節點數具有以下關係:
n0=n2(當n爲偶數時)或n+12(當n爲奇數時)
二叉樹的存儲
在將二叉樹的存儲之前,我們先了解一下樹的存儲方式,常用輸的存儲方式有三種,在介紹之前,我們先把樹的例子放出來,再來看各種存儲方式的不同。
- 雙親表示法
所謂雙親表示法就是會設置一個指示器來指向其雙親所在的位置。那麼我最終應當會存儲爲一個如下的數組:
- 優點:Parent(T,x)可以很快找到雙親
- 缺點:求節點的孩子時就必須遍歷整個結構
- 孩子表示法
所謂孩子表示法就是會在數據後面存儲其孩子節點,但也有兩種方式:
- 方法一:
但是這樣的方法比較浪費空間,因爲你並不知道多叉樹中每個節點一共有多少個孩子節點,而不存在的節點,也必須進行保存爲null; - 方法二:
這樣的方法相對於第一種加入了degree的值,可以更節省空間,但是對樹進行插入或刪除等的操作的時候卻增加了複雜度。
- 方法一:
- 孩子兄弟表示法
孩子兄弟表示法也是二叉樹的一種表示方法,數據的兩端分別存放其左節點的孩子和其兄弟節點。
其數據結構也可以很方便的定義:
typedef struct CSNode{
ElementType data;
Struct CSNode *firstchild,*nextsibling;
} CSNode,*CSTree;
二叉樹的遍歷
所謂遍歷(Traversal)是指沿着某條搜索路線,依次對樹中每個結點均做一次且僅做一次訪問。訪問結點所做的操作依賴於具體的應用問題。
遍歷是二叉樹上最重要的運算之一,是二叉樹上進行其它運算之基礎。
從二叉樹的遞歸定義可知,一棵非空的二叉樹由根結點及左、右子樹這三個基本部分組成。因此,在任一給定結點上,可以按某種次序執行三個操作:
(1)訪問結點本身(N),
(2)遍歷該結點的左子樹(L),
(3)遍歷該結點的右子樹(R)。
在訪問時要求必須先訪問左子樹再訪問右子樹,按照對根節點的訪問順序,二叉樹的遍歷分爲三種:先序中序和後序遍歷。
我們還是以剛纔的二叉樹作爲例子,那麼
- 先序遍歷的結果應該爲:RACDBEF
- 中序遍歷的結果應該爲:CADREBF
- 後序遍歷的結果應該爲:CDAEFBR
用二叉鏈表做爲存儲結構,中序遍歷算法可描述爲:
void InOrder(BinTree T)
{
if(T) { // 如果二叉樹非空
InOrder(T->lchild);
printf("%c",T->data); // 訪問結點
InOrder(T->rchild);
}
} // InOrder
代碼實現
#! /usr/bin/env python
# -*-coding:utf-8 -*-
# Fuction: Create a binary search tree and tranversal in different way
# Coder: Memory
# Date: 2015-04-18
class treeNode():
def __init__(self, data, left, right):
self.data = data
self.left = left
self.right = right
class BTree:
def __init__(self):
self.root = None
def is_empty(self):
if self.root is None:
return True
else:
return False
def insert(self, data):
r = self.root
if r is None:
self.root = treeNode(data, None, None)
return
while True:
# 比根結點小放在左邊
if r.data > data:
if r.left is None:
r.left = treeNode(data, None, None)
break
else:
r = r.left
else:
# 比根結點大放在右邊
if r.right is None:
r.right = treeNode(data, None, None)
break
else:
r = r.right
def traversal(self, root):
if root is None:
return
else:
# 先序遍歷
print root.data
self.traversal(root.left)
# 中序遍歷去掉下一行的註釋
# print root.data
self.traversal(root.right)
# 後序遍歷同上
# print root.data
if __name__ == '__main__':
bt = BTree()
bt.insert(10)
bt.insert(3)
bt.insert(12)
bt.insert(6)
bt.insert(24)
bt.insert(30)
bt.insert(1)
bt.insert(5)
# 若用戶輸入的是數組,就一個個一個地輸入就好了。
bt.traversal(bt.root)
二叉樹的應用和衍生有很多,比如:哈夫曼樹(最優二叉樹),二叉搜索樹等等。將在後續的博文中一一介紹。