课堂笔记:树、森林与二叉树的转换、哈夫曼树
樹、森林與二叉樹的轉換
樹轉換為二叉樹:
1、兄弟加線;
2、保留雙親與第一孩子連線,刪去與其他孩子的連線;
3、順時針轉動,使之層次分明。
樹的前序遍歷等價于二叉樹的前序遍歷,樹的后序遍歷等價于二叉樹的中序遍歷。
森林轉換為二叉樹:
⑴ 將森林中的每棵樹轉換成二叉樹;
⑵ 從第二棵二叉樹開始,依次把后一棵二叉樹的根結點作為前一棵二叉樹根結點的右孩子,當所有二叉樹連起來后,此時所得到的二叉樹就是由森林轉換得到的二叉樹。
二叉樹轉換為樹或森林:
⑴ 加線——若某結點x是其雙親y的左孩子,則把結點x的右孩子、右孩子的右孩子、……,都與結點y用線連起來;
⑵ 去線——刪去原二叉樹中所有的雙親結點與右孩子結點的連線;
⑶ 層次調整——整理由⑴、⑵兩步所得到的樹或森林,使之層次分明。
森林的遍歷
森林有兩種遍歷方法:
⑴前序(根)遍歷:前序遍歷森林即為前序遍歷森林中的每一棵樹。
⑵后序(根)遍歷:后序遍歷森林即為后序遍歷森林中的每一棵樹。
最優二叉樹-哈夫曼樹及哈夫曼編碼
相關概念
葉子結點的權值:對葉子結點賦予的一個有意義的數值量。
二叉樹的帶權路徑長度:設二叉樹具有n個帶權值的葉子結點,從根結點到各個葉子結點的路徑長度與相應葉子結點權值的乘積之和。
哈夫曼樹:給定一組具有確定權值的葉子結點,帶權路徑長度最小的二叉樹。
哈夫曼樹的特點:
1、權值越大的葉子結點越靠近根結點,而權值越小的葉子結點越遠離根結點。
2、只有度為0(葉子結點)和度為2(分支結點)的結點,不存在度為1的結點。
哈夫曼算法基本思想:
⑴ 初始化:由給定的n個權值{w1,w2,…,wn}構造n棵只有一個根結點的二叉樹,從而得到一個二叉樹集合F={T1,T2,…,Tn};
⑵ 選取與合并:在F中選取根結點的權值最小的兩棵二叉樹分別作為左、右子樹構造一棵新的二叉樹,這棵新二叉樹的根結點的權值為其左、右子樹根結點的權值之和;
⑶ 刪除與加入:在F中刪除作為左、右子樹的兩棵二叉樹,并將新建立的二叉樹加入到F中;
⑷ 重復⑵、⑶兩步,當集合F中只剩下一棵二叉樹時,這棵二叉樹便是哈夫曼樹。
哈夫曼算法的存儲結構
設置一個數組huffTree[2n-1]保存哈夫曼樹中各點的信息,數組元素的結點結構 。
偽代碼
1、數組huffTree初始化,所有元素結點的雙親、左 右孩子都置為-1;
2、數組huffTree的前n個元素的權值置給定值w[n];
3、進行n-1次合并
3.1、在二叉樹集合中選取兩個權值最小的根結點,其下標分別為i1, i2;
3.2、將二叉樹i1、i2合并為一棵新的二叉樹k(初值為n;依次遞增);
哈夫曼樹應用——哈夫曼編碼
編碼:給每一個對象標記一個二進制位串來表示一組對象。
例:ASCII,指令系統
等長編碼:表示一組對象的二進制位串的長度相等。
不等長編碼:表示一組對象的二進制位串的長度不相等。
前綴編碼:一組編碼中任一編碼都不是其它任何一個編碼的前綴 。
前綴編碼保證了在解碼時不會有多種可能。
線索二叉樹
二叉樹的遍歷運算是將二叉樹中結點按一定規律線性化的過程。
當以二叉鏈表作為存儲結構時,只能找到結點的左、右孩子信息,而不能直接得到結點在遍歷序列中的前驅和后繼信息。
要得到這些信息可采用以下兩種方法:
第一種方法是將二叉樹遍歷一遍,在遍歷過程中便可得到結點的前驅和后繼,但這種動態訪問浪費時間;
第二種方法是充分利用二叉鏈表中的空鏈域,將遍歷過程中結點的前驅、 后繼信息保存下來。
在有n個結點的二叉鏈表中共有2n個鏈域,但只有n-1個有用的非空鏈域,其余n+1個鏈域是空的。 可以利用剩下的n+1個空鏈域來存放遍歷過程中結點的前驅和后繼信息。
線索鏈表
線索:將二叉鏈表中的空指針域指向前驅結點和后繼結點的指針被稱為線索;
線索化:使二叉鏈表中結點的空鏈域存放其前驅或后繼信息的過程稱為線索化;
線索二叉樹:加上線索的二叉樹稱為線索二叉樹。
線索二叉樹的存儲結構:線索鏈表
結點結構
二叉樹的遍歷方式有4種,故有4種意義下的前驅和后繼,相應的有4種線索二叉樹: ⑴ 前序線索二叉樹;⑵ 中序線索二叉樹;⑶ 后序線索二叉樹;⑷ 層序線索二叉樹。
中序線索二叉樹
中序線索鏈表類的聲明
中序線索鏈表的建立——構造函數
分析:建立線索鏈表,實質上就是將二叉鏈表中的空指針改為指向前驅或后繼的線索,而前驅或后繼的信息只有在遍歷該二叉樹時才能得到。
建立二叉鏈表(帶有標志位)—>遍歷二叉樹,將空指針改為線索
建立帶有標志位的二叉鏈表
中序線索化二叉樹:遞歸實現
基本思想: 在遍歷的過程中完成線索化 可以采用前序、中序、后序遍歷建立前序線索二叉樹、中序線索二叉樹和后序線索二叉樹。
中序線索二叉樹的構造方法:中序線索化根結點的左子樹;對根結點進行線索化;中序線索化根結點的右子樹;
函數設置形參root和全局變量pre,分別表示要處理的樹的根結點和其前驅結點
線索鏈表的遍歷算法:中序遍歷中序線索樹
查找第一個節點:先從樹的根出發,一直沿左指針,找到“最左”(它一定是中序的第一個結點);
結點后繼的確定:一個結點的右指針如果是線索,則右指針就是下一個要遍歷的結點, 如果右指針不是線索,則它的中序后繼是其右子樹的“最左”結點;
遍歷何時停止:一個節點的右指針==NULL
在中序線索樹中查找結點的中序遍歷的后繼
線索鏈表的遍歷算法:中序遍歷中序線索樹
template<class T> void InThrBiTree<T>::InOrder(ThrNode<T> *root){ ThrNode<T>* p = root; if (root==NULL) return;while (p->ltag==Child){ p = p->lchild; } cout<<p->data<<" "; while (p->rchild!=NULL){ p = Next(p); cout<<p->data<<" ";}cout<<endl; }總結
以上是生活随笔為你收集整理的课堂笔记:树、森林与二叉树的转换、哈夫曼树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于简单的机器学习方法等异常值识别方法(
- 下一篇: 控制字符输出java_令人伤透脑筋的ja