六.树
1.樹的定義
樹(Tree) 是n(n>=0)個結點的有限集.
n=0時稱為空樹.
在任意一棵非空樹中:
(1)有且僅有一個特定的稱為(Root)的結點;
(2)當n>1時,其余結點可分為m(m>0)個互不相交的有限集T1,T2…Tm,其中,每一個集合本身又是一棵樹,并且稱為根的子樹(SubTree),如圖6-2-1所示.
2.結點分類
結點擁有的子樹數稱為結點的度(Degree)
度為0的結點稱為葉節點(Leaf)或者終端結點
度不為0的結點稱為非終端結點或者分支結點
除根節點之外,分支結點也稱內部結點
樹的度 是樹內各個結點的度的最大值
3.結點之間的關系
結點的子樹的根稱為該結點的孩子(Child) ,相應的,該結點稱為孩子的雙親(Parent)
同一個雙親的孩子之間互稱為兄弟(Sibling)
結點的祖先 是從根到該結點所經分支上的所有結點
以某結點為根的子樹中的任一結點都稱為該結點的子孫
4.樹的其他相關概念
結點的層次(Level) 從根開始定義起,根為第一層,根的孩子為第二層.
雙親在同一層的結點互稱為堂兄弟
樹中結點的最大層次稱為樹的深度(Depth)或高度
如果將樹中結點的子樹看成是從左到右是有次序的,不能互換的,則稱該樹為有序樹 ,否則稱為無序樹
森林(Forest) 是m(m>=0)棵互不相交的樹的集合
5.樹的存儲結構
雙親表示法
以一組連續空間存儲樹的結點,同時在每個結點中,附設一個指示器指示其雙親結點在數組中的位置(根結點的位置域設置為-1)
孩子表示法
把每個結點的孩子結點排列起來,以單鏈表作存儲結構,則n個結點有n個孩子鏈表.如果是葉子結點則此單鏈表為空.然后n個頭指針又組成一個線性表,采用順序存儲結構,存放進一個一維數組中
使用多重鏈表,每個結點有多個指針域,其中每個指針指向一棵子樹的根節點,我們把這種方法叫做多重鏈表表示法
孩子兄弟表示法
任意一棵樹,它的結點的第一個孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的.因此,設置連個指針,分別指向該結點的第一個孩子和此結點的右兄弟
6.二叉樹
二叉樹(Binary Tree) 是n(n>=0)個結點的有限集合,該集合或者為空集(稱為空二叉樹),或者由一個根節點和兩棵互不相交的,分別稱為根節點的左子樹和右子樹的二叉樹組成
特點:
1.每個結點最多有兩棵子樹,所以二叉樹中不存在度大于2的結點
2.左子樹和右子樹是有順序的,次序不能任意顛倒
3.即使樹中某結點只有一棵子樹,也要區分它是左子樹還是右子樹
二叉樹具有的五種基本形態:
1.空二叉樹
2.只有一個根節點
3.根節點只有一個左子樹
4.根節點只有一個右子樹
5.根節點既有左子樹又有右子樹
6.1 特殊二叉樹
斜樹:
所有結點都只有左子樹的二叉樹叫左斜樹
所有結點都只有右子樹的二叉樹叫右斜樹
斜樹有一個很明顯的特點,每一層只有一個結點,結點個數和二叉樹的深度相同
滿二叉樹:
在一棵二叉樹中,所有的分支結點都存在左子樹和右子樹,并且所有葉子都在同一層上,這樣的二叉樹稱為滿二叉樹
滿二叉樹的特點:
1.葉子只能出現在最下一層
2.非葉子節點的度一定是二
3.在同樣深度的二叉樹中,滿二叉樹的結點最多,葉子數最多
完全二叉樹:
對一棵具有n個結點的二叉樹按層序編號,如果編號為i(1<=i<=n)的結點與同樣深度的滿二叉樹中編號為i的結點在二叉樹中的位置完全相同,則這棵二叉樹稱為完全二叉樹
完全二叉樹特點:
1.葉子結點只能出現在最下面兩層
2.最下層的葉子一定集中在左部連續位置
3.倒數第二層,若有葉子結點,一定都在右部連續位置
4.如果結點度為1,則該結點只有左孩子,即不存在只有右子樹的情況
5.同樣結點數的二叉樹,完全二叉樹的深度最小
6.2二叉樹的性質
(1)在二叉樹的第i層上至多有2i-1個結點(i>=1)
(2)深度為k的二叉樹至多有2K-1個結點(k>=1)
(3)對任何一棵二叉樹T,如果其終端結點數為n0,度為2的節點數為n2,則n0=n2+1;
(4)具有n個結點的完全二叉樹深度為(log2n)+1
(5)如果對一棵有n個結點的完全二叉樹(其深度為(log2n)+1)的結點按層序編號(從第一層到第(log2n)+1層,每層從左到右),對任一結點i(1<=i<=n)有:
若 i=1,則該結點是二叉樹的根,無雙親, 否則,編號為 [i/2] 的結點為其雙親結點;
若 2i>n,則該結點無左孩子, 否則,編號為 2i 的結點為其左孩子結點;
若 2i+1>n,則該結點無右孩子結點, 否則,編號為2i+1 的結點為其右孩子結點。
6.3二叉樹的順序存儲結構
順序存儲:一般用于完全二叉樹
二叉鏈表:二叉樹每個結點最多有兩個孩子,所以設計一個數據域和兩個指針域
如果有需要,還可以增加一個指向其雙親的指針域,稱為三叉鏈表
6.4 遍歷二叉樹
二叉樹的遍歷(traversing binary tree) 是指從根節點出發,按照某種次序依次訪問二叉樹中所有結點,似的每個結點被訪問一次,且僅被訪問一次.
二叉樹的遍歷方法:
1.前序遍歷:若二叉樹為空,則空操作返回;否則先訪問根節點,然后前序遍歷左子樹,再前序遍歷右子樹
Void PreorderTraverse(BiTree T)
{
If(T==NULL){
return ;
}
Printf(“%c”,T->data);
PreorderTraverse(T->lchild);
PreorderTraverse(T->rchild);
}
2.中序遍歷:若樹為空,則空操作返回;否則從根節點開始(注意并不是從根節點開始),中序遍歷根節點的左子樹,然后訪問根節點,最后中序遍歷右子樹
Void PreorderTraverse(BiTree T)
{
If(T==NULL){
return ;
}
PreorderTraverse(T->lchild);
Printf(“%c”,T->data);
PreorderTraverse(T->rchild);
}
3.后序遍歷:若樹為空,則空操作返回;否則從左到右先葉子結點后結點的方式遍歷訪問左右子樹,最后訪問根節點
Void PreorderTraverse(BiTree T)
{
If(T==NULL){
return ;
}
PreorderTraverse(T->lchild);
PreorderTraverse(T->rchild);
Printf(“%c”,T->data);
}
4.層序遍歷:若樹為空,則空操作返回,否則從樹的第一層,也就是根節點開始訪問,從上而下逐層遍歷,在同一層中,按照從左到右的順序對結點逐個訪問
二叉樹遍歷的性質:
已知前序遍歷序列和中序遍歷序列,可以唯一確定一棵二叉樹
已知后續遍歷序列和中序遍歷序列,可以唯一確定一棵二叉樹
已知前續遍歷序列和后序遍歷序列,是不能確定一棵二叉樹
建立二叉樹使用了遞歸的原理
指向前驅和后繼的指針稱為線索,加上線索的二叉鏈表稱為線索鏈表,相應的二叉樹稱為線索二叉樹(Threaded Binary Tree)
對二叉樹以某種次序遍歷使其變為線索二叉樹的過程稱作是線索化
線索化的過程就是在遍歷的過程中修改空指針的過程
6.5樹,森林,二叉樹之間的轉換
樹轉換為二叉樹:
加線。就是在所有兄弟結點之間加一條連線;
抹線。就是對樹中的每個結點,只保留他與第一個孩子結點之間的連線,刪除它與其它孩子結點之間的連線;
旋轉。就是以樹的根結點為軸心,將整棵樹順時針旋轉一定角度,使之結構層次分明。
森林轉換為二叉樹
森林是由若干棵樹組成,可以將森林中的每棵樹的根結點看作是兄弟,由于每棵樹都可以轉換為二叉樹,所以森林也可以轉換為二叉樹。
將森林轉換為二叉樹的步驟是:
(1)先把每棵樹轉換為二叉樹;
(2)第一棵二叉樹不動,從第二棵二叉樹開始,依次把后一棵二叉樹的根結點作為前一棵二叉樹的根結點的右孩子結點,用線連接起來。當所有的二叉樹連接起來后得到的二叉樹就是由森林轉換得到的二叉樹。
6.6 赫夫曼樹
樹結點間的邊相關的數叫做權(Weight)
從樹中的一個結點到另一個結點之間的分支構成兩個結點之間的路徑,路徑上的分支數目稱作路徑長度
樹的路徑長度是從樹根到每一個結點的路徑長度之和
帶權路徑長度WPL最小的二叉樹稱作赫夫曼樹,也有書中稱作最優二叉樹
赫夫曼算法描述:
1.根據給定的n個權值{w1,w2…wn}構成n棵二叉樹(只含一個節點)的集合F= {T1,T2,…,Tn}.,其中每顆二叉樹Ti中只有一個帶權為Wi的根節點,其左右子樹為空。
2.在F中選取兩顆根節點的權值最小的樹作為左右子樹構造一顆新的二叉樹,并且新的二叉樹的根節點的權值為左右子樹根節點上的權值之和。
3.在F中刪除這兩棵樹,將新的到的二叉樹加入F中。
4.重復二三,直到F中只剩下一棵樹為止,這就是赫夫曼樹。
赫夫曼編碼:
假設有一段需要編碼的字符集{d1,d2,…,dn},求得各個字符在電報中出現的頻率集合為{w1,w2,…,wn},以d1,d2,…,dn作為葉子節點,以w1,w2,…,wn作為相應葉子節點的權值來構造一顆赫夫曼樹。并且規定好赫夫曼樹的左分支代表0,右分支代表1(即一個結點的左孩子為0,右孩子為1),則一個字符的編碼就是從根節點到葉子節點所經過的路徑分支組成的0和1的序列。這就是赫夫曼編碼。通俗來說,就是給你一段字符,按照一種方式或者規則編碼可以使得編碼后所得的二進制串最短.比如說A字符的編碼為01.這樣就可以得到比原來編碼更短的二進制串,壓縮了數據,節約了存儲成本。
總結
- 上一篇: 五.串
- 下一篇: docker搭建lnmp环境错误总结