程序员基本功11树和二叉树
你只管努力,其他的交給天意
1、樹的概念和基本術語
樹是一種非線性的數據結構,如果一組數組節點之間存在復雜的一對多關聯時,程序可以考慮使用樹來存儲這組數據。Treemap本身就是一顆紅黑樹,紅黑樹又是一種特殊的排序二叉樹。
樹:指的是N個有父子關系的節點的有限集合
對于這個集合,它滿足如下條件:
- 節點:樹的最基本組成單元,常包括一個數據元素及若干指針用于指向其他節點
- 節點的度:節點擁有的子樹的個數被稱為節點的度
- 樹的度:樹中所有節點的度的最大值
- 葉子節點:度為0的節點被稱為葉子節點或終端節點
- 分支節點:度不為0的節點
- 子節點、父節點和兄弟節點:節點的子樹的根被稱為子節點,該節點為父節點。具有相同父節點的子節點互稱為兄弟節點
- 節點的層次:節點的層次從根開始算起,跟的層次為1,其余節點的層次值為父節點的穿層次值加1。
- 樹的深度:樹中節點的最大層次值稱為樹的深度
- 有序樹與無序樹:如果樹中節點的各個子樹看成從左到右是有序的,則概述為有序樹,否則為無序樹
- 祖先節點:從根到該節點所經過分支上的所有節點
- 后代節點:以某節點為根的子樹中任一節點
- 深林:森林是2顆或2顆以上互不相交的樹的集合
2、樹的基本操作
- 初始化:通常是一個構造器,用于創建一個空的樹,或者以指定節點為根創建樹
- 為指定節點添加子節點
- 判斷樹是否為空
- 返回根節點
- 返回指定節點(非根節點)的所有子節點
- 返回指定節點的(非葉子節點)的所有子節點
- 返回指定節點(非葉子節點)的第i個子節點
- 返回該樹的深度
- 返回指定節點的位置
3、樹的父節點存儲實現
為了實現這種數據結構,程序必須記錄節點與非節點的父子關系,有倆種選擇:父節點表示法、子節點表示法
定義樹節點時增加一個Parent域,該域用于保存該節點的父節點在數組中的位置索引,通過這種方式記錄書中節點之間的父子關系,添加新節點時將新節點的parent域的值設為其父節點在數組中的索引。
每個節點都可以快速找到它的父節點,但如果要找某個節點的所有子節點就比較麻煩,程序要遍歷整個節點數組。
4、樹的子節點鏈表示法
讓父節點記住它的所有子節點?
5、二叉樹的定義和基本概念
二叉樹指的是每個節點最多只能有倆個子樹的有序樹,左邊的子樹稱為左子樹,右邊的子樹稱為右子樹
樹個二叉樹的倆個重要區別:
- 樹中節點的最大度數沒有限制,二叉樹節點的最大度數為2
- 無序樹的節點無左右之分,而二叉樹的節點有左右之分,也就是說,二叉樹是有序樹
- 二叉樹的性質:
- 二叉樹第i層的節點數目至多為
- 深度為k的二叉樹至多有個節點
- 任何二叉樹中,如果其葉子節點的數量為n0,度為2的子節點數量為n2,則n0=n2+1。
- 具有n個節點的完全二叉樹的深度為
- 對一顆有n個節點的完全二叉樹的節點按層自左向右編號,則對任一編號為i的節點有:
當i=1時,節點i是二叉樹的根;若i>1,則節點的父節點是i/。
若,則節點i有左孩子,左孩子的編號是2i,否則,節點無左孩子,并且是葉子節點。
若,則節點i有右孩子,有孩子的編號是;否則節點無右孩子。
- 對一顆有n個節點的完全二叉樹的節點按層自左向右編號,1~n/2范圍的節點都是有孩子節點的非葉子節點,其余的都是葉子節點。編號為n/2的節點可能只有左子節點,也可能左右子節點都有。
?
6、二叉樹的基本操作
- 初始化:通常是一個構造器,用于創建一個空的樹,或者以指定節點為根創建二叉樹
- 為指定節點添加子節點
- 判斷二叉樹是否為空
- 返回根節點
- 返回根節點的父節點
- 返回指定節點的左子節點
- 返回指定節點的右子節點
- 返回該二叉樹的深度
- 返回指定節點的位置
實現二叉樹這種數據結構,右三種選擇:
- 順序存儲:采用數組來記錄二叉樹的所有節點
- 二叉鏈表存儲:每個節點保留一個left、right域,分別指向其左右子節點
- 三叉鏈表存儲:每個節點保留left、right和parent域,分別指向左、右子節點和父節點。
7、二叉樹的順序存儲的實現
二叉樹每層的節點數最多為,這個二叉樹最多能包含節點為,因此只要定義一個的數組即可儲存這棵樹。二叉樹采用順序存儲可能會造成一定的空間浪費。
8、二叉樹和二叉鏈表存儲的實現
對于二叉鏈表的二叉樹,因為程序采用鏈表來記錄樹中所有節點,所以添加節點沒有限制,也不會像順序存儲那樣產生大量的空間浪費。這種二叉鏈表的存儲方式在遍歷樹節點時效率不高,指定節點訪問父類節點也比較困難,程序必須采用遍歷二叉樹的方式搜索其父節點。
為了克服二叉鏈表存儲方式中訪問父類節點不方便的問題,可以將二叉鏈表擴展成三叉鏈表。三叉鏈表存儲方式是二叉鏈表的一種改進,通過為樹節點增加一個parent引用,可以讓每個節點都能方便的訪問父節點。
遍歷二叉樹指的是按照某種規律依次訪問二叉樹的每個節點,對二叉樹的遍歷過程就是將非線性結構的二叉樹中的節點排列在一個線性序列上升的過程。如果采用順序結構保存二叉樹,程序遍歷二叉樹將非常容易,直接遍歷底層數組即可,如果采用鏈表保存二叉樹的節點,則有倆中遍歷方式:
深度優先遍歷:這種遍歷將先訪問到樹中最深層析的節點。它右可分為3中(前序、中序、后序)
廣度優先遍歷:逐層訪問每層的節點,先訪問根節點,然后訪問第二層節點,廣度遍歷法又被稱為按層遍歷
9、先序遍歷二叉樹
DLR(L:左子樹、D:根、R:右子樹)
10、中序遍歷二叉樹
LDR
11、后續遍歷二叉樹
LRD
12、廣度優先遍歷二叉樹
先遍歷二叉樹的第一層,再遍歷根節點的倆個子節點,逐層遍歷二叉樹所有節點。
為了實現廣度優先遍歷,可以借助FIFO特征隊列來實現:
13、森林、樹和二叉樹之間的轉換
三者之間一一映射,可以相互轉換
多叉樹向二叉樹轉換:
- 加虛線:同一個父節點的相鄰兄弟節點之間加虛線
- 抹實線:每個節點只保留它與最左子節點的連線,與其他子節點的連線都被抹掉
- 虛改實:虛線改實線
二叉樹向多叉樹、森林恢復:
- 加虛線:若某節點I是父節點的左子節點,則將該節點I的右孩子鏈的所有節點分別與I的父節點添加連線
- 抹線:把有虛線的節點與原父節點的連線抹去
- 整理:虛改實并按層排列
14、樹的鏈表存儲
因為多叉樹和二叉樹可以自由轉換,因此,普通樹可以以二叉樹的形式保存,實際需要的時候,再將二叉樹轉換為普通樹
通常使用三叉鏈表來保存二叉樹
15、哈夫曼樹的概念和用途
哈夫曼樹又被稱為最優二叉樹,是一類帶權路徑最短的二叉樹,在信息檢索時常用。
節點之間的路徑長度:從一個節點到另一個節點之間的分支數量稱為倆個節點之間的路徑長度
樹的路徑長度:從根節點到樹中每一個節點的路徑長度之和
節點的帶權路徑長度:從該節點到根節點之間的路徑長度與節點上權的乘機
樹的帶權路徑長度:樹中所有葉子節點的帶權路徑長度之和
帶權路徑最小的二叉樹被稱為哈夫曼樹或最有二叉樹。
對于具有n個葉子節點的哈夫曼樹,一共需要個節點。
【對于二叉樹來說,有三種類型節點:度數為0、1、2。而哈夫曼樹的非葉子節點都是由倆個節點合并產生】
16、創建哈夫曼樹
17、哈夫曼編碼
從哈夫曼根節點開始,對左子樹分配代碼“0”,對右子樹分配代碼“1”,一直到達葉子節點,然后,將從樹根沿每條路徑到達子節點的代碼排列起來,便得到了每個葉子節點的哈夫曼編碼。
采用哈夫曼樹原理構造的二進制編碼,使電文總最短。
哈夫曼編碼有一條規矩:假設有N個葉子節點需要編碼,最終得到的哈夫曼一定有N層,哈夫曼編碼得到的二進制碼的最大長度為N-1.
18、排序二叉樹的概念和實現
排序二叉樹是一種特殊結構的二叉樹,通過它可以非常方便地對樹中所有節點進行排序和索引。排序二叉樹要么是空樹,要么有以下性質:
- 若它的左子樹不空,則左子樹上所有節點的值均小于它的根節點的值
- 若它的右子樹不空,則右子樹上所有節點的值均大于它的根節點的值
- 它的左右子樹也分別為排序二叉樹
創建排序二叉樹的步驟:
?當程序從排序二叉樹中刪除一個檢點后,為了保持為排序二叉樹,必須對該排序二叉樹進行維護。
被刪除的節點是葉子節點,則只需將它從父節點中刪除
被刪除節點p只有左子樹,將p的左子樹pL添加成p的父節點的左子樹即可;被刪除節點p只有右子樹,將p的右子樹pR添加成p的父節點的右子樹即可
若被刪除節點p的左右樹均為空:
將pL設為p的父節點q的左或右子節點(取決于p是其父節點q的左右子節點),將pR設為p節點的中序前趨節點s的右子節點(s是pL最右下的節點,也就是pL子樹中最大的節點)
以p節點的中序前趨或后繼替代p所指節點,然后再從原排序二叉樹中刪除中序前趨或后繼節點?
19、紅黑樹的概念和實現
排序二叉樹雖然可以快速檢索,但如果插入的節點本身就是有序的,那么最后排序二叉樹將變成鏈表:只有左節點或右節點。這時排序二叉樹就是普通鏈表,檢索效率就會很差。
紅黑樹的提出為了改善排序二叉樹的不足。
紅黑樹并不是真正的平衡二叉樹,實際應用中,紅黑樹的統計性能要高于平衡二叉樹,但極端性能略差
紅黑樹在原有二叉樹上增加如下幾個要求:
總結
以上是生活随笔為你收集整理的程序员基本功11树和二叉树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员基本功05表达式中的陷阱
- 下一篇: 剑指offer(04)重建二叉树