二叉樹
- 每個結點最多有兩顆子樹,結點的度最大爲2
- 左子樹和右子樹是有順序的,次序不能顛倒
- 節點數爲n的樹 深度至多爲n 至少爲log2(n+1)向下取整
- 對於任何一棵非空的二叉樹,如果葉節點個數爲n0,度數爲2的節點個數爲n2,則有: n0 = n2 + 1
存儲二叉樹結構的方法一般有三種,數組、鏈表、遊標
滿二叉樹
高度爲h的滿二叉樹擁有剛剛好(2^h+1 )-1個節點
完全二叉樹
若二叉樹高度爲h,除h層外其他所有層節點個數都達到了最大個數。若h層有葉節點,則所有的葉節點從左到右排列。這就是完全二叉樹
-
具有n的結點的完全二叉樹的深度爲log2n+1.
-
如果有一顆有n個節點的完全二叉樹的節點按層次序編號,對任一層的節點i(1<=i<=n)有
- 如果i=1,則節點是二叉樹的根,無雙親,如果i>1,則其雙親節點爲[i/2],向下取整
- 如果2i>n那麼節點i沒有左孩子,否則其左孩子爲2i
- 如果2i+1>n那麼節點沒有右孩子,否則右孩子爲2i+1
tips: 編號後,左子節點的編號是父節點編號的兩倍
二叉樹的遍歷
前序遍歷:根—左—右。
-
遞歸實現
-
非遞歸實現
思路:每次訪問樹的左節點,並將節點入棧。如果左節點爲空,就取棧頂出棧,訪問棧頂節點的右節點,並繼續訪問入棧訪問左節點。代碼如下:
void preOrderTraverse(Tree t) {
Stack s;
Tree tmp = t;
while((tmp != NULL) || !isEmpty(&s)) {
while(tmp != NULL) {
Push(&s, tmp);
visit(&tmp);
tmp = tmp->lchild;
}
if(!isEmpty(&s)) {
Pop(&s, &tmp);
tmp = tmp->rchild;
}
}
}
中序遍歷: 左-根-右
-
遞歸實現
-
非遞歸實現
- 若其左孩子不爲空,則將t入棧,並將t的左孩子設置爲當前的t
- 若其左孩子爲空,則取棧頂元素並進行出棧操作,訪問該結點。然後將當前的t置爲棧頂結點的右孩子
- 直到t爲空並且棧爲空,則遍歷結束。
void inOrderTraverse(Tree t) {
Stack s;
Tree tmp = t;
while((tmp != NULL) || !isEmpty(&s)) {
while(tmp != NULL) {
Push(&s, tmp);
tmp = tmp->lchild;
}
if(!isEmpty(&s)) {
Pop(&s, &tmp);
visit(&tmp);
tmp = tmp->rchild;
}
}
}
後序遍歷: 左-右-根
-
遞歸實現
-
非遞歸實現
確保在訪問父節點之前左右子節點都已經被訪問。當前節點如果沒有子節點,或者當前節點的子節點都被訪問的時候,可以訪問當前節點。否則將當前節點的子節點入棧。
void postOrderTraverse(Tree t) {
Stack s;
Tree cur = NULL;
Tree pre = NULL;
Push(&s, t);
while(!isEmpty(&s) {
Top(&s, &cur);
if((cur->lchild == NULL && cur->rchild == NULL)) ||
(cur->lchild == NULL && pre != NULL && pre == cur->rchild) ||
(cur->rchild == NULL && pre != NULL && pre == cur->lchild)) {
Pop(&s, &cur);
visit(cur);
pre = cur;
} else {
if(cur->lchild) {
Push(&s, cur->lchild);
}
if(cur->rchild) {
Push(&s, cur->rchild);
}
}
}
}
}
二叉樹的創建
-
使用訪問序列建立二叉樹,如 先序:ABDCEGFHI 中序:DBAEGCHFI
tips: 如果僅僅知道二叉樹的先序遍歷和後序遍歷,無法確定二叉樹
-
使用廣義表來構造,如:A(B(D), C(E( ,G), F(H,I)))
線索樹
n個結點的二叉樹有2n個鏈域,其中真正有用的是n – 1個,其它n + 1個都是空域。 爲了充分利用結點中的空域,使得對某些運算更快,如前驅或後繼等運算。
二叉樹的應用:霍夫曼樹
參考這裏
https://blog.csdn.net/shuangde800/article/details/7341289
主要有兩類:
- 霍夫曼樹構造條件判斷樹,使其比較次數最少
- 霍夫曼編碼