二叉樹的性質
性質1:
在二叉樹的第i層上至多有2^(i-1)個結點(i>0)
因為一個節點度不大于2(即每個結點只能有兩棵子樹),如果假設這棵二叉樹是一棵滿二叉樹,那么每個結點都有兩棵子樹,按每層來看的話,會發現它是首項為1,公比為2的等比數列,所以第i層最多有2^(i-1)個結點(i>0)
性質2:
一棵深度為k的二叉樹中,最多有2^k-1個結點
其實這也很好得出這個性質,既然每層的結點數量就是等比數列的一項,那么深度為k的樹,假設為滿二叉樹,那么結點總數就是等比數列求和,所以,一棵深度為k的二叉樹中,最多有2^k-1個結點
性質3:
具有n個結點的完全二叉樹的深度k為[log2n]+1
其實就是性質2的逆推,假設有棵深度為x的完全二叉樹,那么他的結點總數的范圍為2^(k-1)-1 < n <= 2^k-1,兩邊同時取對數得k-1 < og2n <= k,具有n個結點的完全二叉樹的深度k為[log2n]+1
性質4:
對于一棵非空的二叉樹,如果葉子結點數為n0,度為2的結點數為n2,
則n0 = n2+1
整棵樹的結點數: n = n0+n1+n2 (n0葉子結點數,n1度為1的結點數,n2度為2的結點數)
根據節點度的定義子結點的的數量為: n0×0+n1×1+n2×2
子節點的數量為:n-1 (除根以外每個結點都是子節點)
所以解得 n0 = n2+1
性質5:
對于具有n個節點的完全二叉樹,如果按照從上至下和從左至右的順序對二叉樹中所有結點進行從1的編號,則對于任意的序號為i結點,有:
- 如果i>1,則序號為i的結點的雙親結點為i/2,如果i==1,則序號為i的結點是根節點,無雙親結點
- 如果2i<=n,則序號為i的結點的左孩子節點的序號為2i,否則i結點無左孩子
- 如果2i+1<=n,則序號為i的結點的右孩子節點的序號為2i,否則i結點無右孩子
注意:性質1,2,4所有二叉樹都通用,性質3,5只有完全二叉樹適用
二叉樹的存儲結構
二叉樹的存儲方式也可以分為順序存儲結構和鏈式存儲結構兩種存儲結構
二叉樹的順序存儲結構
這里的順序存儲也是用一組連續的存儲單元依次從上至下,從左至右存儲二叉樹上的節點元素。對于完全二叉樹來說樹中結點的序號都是按照從上至下,從左至右進行編排的,所以結點的序號可以唯一的反映節點之間的邏輯關系(性質5)
存儲在數組中,數組下表從零開始
數組下標 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
-------|----------------------------------
數據 | A | B | C | D | E | F | G | H | I
如果是一般的二叉樹的話,如果我在對他進行從上至下,從左至右進行編號時就不能很好的反映數組元素之間的關系了,如果我們進行適當的改造,通過添加一些結點,把他補成一顆完全二叉樹,那么再進行編號,就可以進行順序存儲了
數組下標 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
-------|--------------------------------------------
數據 | A | B | C | D | E | 0 | 0 | 0 | 0 | 0 | F
由此可以看出,這樣的存儲方式,會造成很多空間的浪費,而且如果要進行對樹上元素進行刪除、插入操作需要移動大量的數據元素,因此二叉樹不宜采用順序存儲結構
二叉樹的鏈式存儲結構
二叉樹的鏈式存儲結構就是,用類似于鏈表的存儲方法來存儲樹上元素的邏輯關系,即用指針來表示元素之間的邏輯關系
data是數據域,leftChild和rightChild是指針域,leftChild是
指向左兒子的指針,rightChild是指向有兒子的指針,當左兒子或右兒子為空時,相應的指針域也為空
代碼描述
//存儲的數據類型
typedef char DataType
typedef struct node
{
DataType data; //數據域
struct node* leftChild; //左兒子
struct node* rightChild; //右兒子
}BinNode;
typedef BinNode* BinTree;
這是二叉鏈表的定義,除此之外還有三叉鏈表,三叉鏈表比起二叉鏈表多了一個指向雙親結點的指針域,如圖所示
代碼描述
//存儲的數據類型
typedef char DataType
typedef struct node
{
DataType data; //數據域
struct node* leftChild; //左兒子
struct node* rightChild; //右兒子
struct node* parent; //雙親
}BinNode;
typedef BinNode* BinTree;