數據結構與算法系列文章
數據結構與算法 - 時間複雜度
數據結構與算法 - 線性表
數據結構與算法 - 樹形結構git
1、樹
2、二叉樹
3、樹、森林與二叉樹的轉換github
樹形結構 是數據元素(結點)之間有分支,而且具備層次關係的結構,可用於表示數據元素之間存在的一對多關係。
樹(Tree) 是由n(n≥0)個結點構成的有限集合,當n=0時稱爲空樹。若樹非空,則具備如下兩個性質:
(1)有且僅有一個特定的結點,稱爲根(Root)。
(2)其他的結點可分爲m個互不相交的集合T1,T2,…,Tm,其中每個集合都是一棵樹,而且稱爲根的子樹( Subtree)。
以下圖所示是有13個結點的樹,A是根,其他結點分紅三個互斥的集合T1={B,E,F,K,L}、T2={C,G}、T3={D,H,I,J,M},T一、T二、T3都是A的子樹,其自己也是一棵樹。算法
樹的基本術語:
樹結點( Tree Node) :樹中一個獨立單元。包含一個數據元素及若干指向其子樹的分支,如上圖中的A、B、C、D等。
樹根(Root) :樹中惟一沒有前驅的結點,如上圖中的A結點。
結點的度( Node Degree) :結點擁有的子樹數,稱爲結點的度。例如,在上圖中A的度爲3,B的度爲2,K的度爲0。
樹的度( Tree Degree) :樹中各結點的度的最大值。如上圖中樹的度爲3。
樹葉(Leaf) :度爲0的結點。例如,在圖中,K、L、F、G、一、J、M都是樹葉,也稱葉結點。除根和葉子之外的其餘結點稱爲中間結點。
雙親( Parent)和孩子( Child) :把一個樹結點的直接前驅稱爲該結點的雙親;反之;把一個樹結點的全部直接後繼稱爲該結點的孩子。例如,上圖中,結點B是結點A的孩子,結點A是結點B的雙親。
兄弟( Sibling) :同一雙親的孩子之間互稱爲兄弟。例如,上圖中,結點K、L互爲兄弟,結點H、I、J互爲兄弟。將這些關係進一步推廣,結點的祖先就是從根到該結點的所經分支上的全部結點。以某結點爲根的子樹中的任一結點都稱爲該結點的子孫。此外雙親在同一層上的結點互爲堂兄弟.
樹的層次( Level)和深度( Depth) :從根算起,根爲第一層,根的孩子爲第二層,樹中任一結點的層次等於它的雙親的層次加1。樹中各結點層次的最大值稱爲樹的深度或高度。例如,上圖中的樹的深度爲4。
有序樹和無序樹( Ordered Tree8。 Unordered Tree) :若是樹中結點的各子樹可當作從左至右是有次序的(即不能互換),則稱該樹爲有序樹,不然稱爲無序樹。在有序樹最左邊子樹的根稱爲第一孩子,最右邊子樹的根稱爲最後一個孩子。
森林( Forest) :m(m≥0)棵互不相交的樹的集合。對樹中每一個結點而言,其子樹的集合即爲森林。由此也能夠以森林和樹的相互遞歸定義來描述樹。數組
樹是一種非線性結構。爲了存儲一探樹,必須把樹中各結點之間一對多的關係反映在存儲結構中。因爲在一個m階的普通樹中,每個結點的孩子但是0~m個,因此相對於二又樹而言,樹的存錯結構要複雜,通常有以下幾種存儲結構:微信
雙親表示法是以一組連續空間存儲樹的結點,同時在每一個結點中附設一個標誌指示其雙親結點在表中的位置,該存儲結構定義以下;網絡
因爲樹中的每一個結點可能有多棵子樹,所以能夠採用多重鏈表來表示,即每一個結點有多個指針域,分別指向其孩子結點。
如圖6-13所示,樹的孩子表示法須要按照樹的度m爲每一個結點分配指針域,而每一個結點的孩子個數可不一樣,當m很大時,指針域的存儲單元利用率很低。若是按每一個結點的實際孩子數來分配指針單元,結點的大小可變,會給存儲管理帶來不便。一個較好的解決辦法就是爲每一個結點創建一個孩子鏈表,n個結點的樹由n個這樣的單鏈表組成,每一個鏈表的表頭結點存放該結點的值和指向其孩子的頭指針,如圖614所示數據結構
孩子兄弟表示法又稱樹的二又鏈表表示法。樹中的每一個結點由三個域組成:data域 結點的數據信息, firstchild域爲指向結點的第一個孩子的指針, nextbrother域爲指向下一個兄弟的指針,以下圖所示。
由下圖能夠看出,每一個結點的左指針指向孩子結點,而右指針指向兄弟結點,而且根結點的右指針爲空。樹的孩子兄弟表示法爲實現樹、森林與二又樹之間的轉換提供了基礎。3d
二叉樹 就是度爲2的有序樹,是最重要的一種樹形結構。二又樹的存儲和處理比普通樹簡單,同時普通樹均可以方便地轉化爲二又樹來存儲和處理。
二叉樹( Binary Tree) 是一種特殊的樹形結構。定義以下:
(1)由n(n≥0)個結點所構成的集合,此集合能夠爲空。
(2)二叉樹的根結點下可分爲兩個互不相交的子樹,子樹有左右之分,次序不能任意顛倒,稱爲左子樹和右子樹:且左右子樹均爲二叉樹。指針
二叉樹是有序樹的特例,具備下列重要性質:
性質一、在二叉樹的第i層上至多有2^(i-1)個結點(i>=1)。
性質二、深度爲k的二叉樹至多有2^(k) - 1個結點,(k>=1)。
性質三、對任何一顆二叉樹T,若是其終端結點數爲n0,度爲2的結點數爲n2,則n0 = n2 + 1;
性質四、具備n個結點的徹底二叉樹的深度爲 (logn以2爲底的對數 + 1) 。
性質五、若是對一棵有n結點的深度爲(logn以2爲底的對數 + 1) ,徹底二叉樹的結點按層序編號,同層按從左至右,則對任一結點i(1 ≤ i ≤ n)。因而有:
(1)若是=1,則結點i是二叉樹的根,無雙親;若是i>1,則其雙親 PARENT(i)是結點i/2。
(2)若是2i>n,則結點i無左孩子(結點i爲葉子結點);不然,其左孩子 LCHILD(i)是結點2i。
(3)若是2i+1>n,則結點i無右孩子;不然,其右孩子 RCHILD(i)是結點2i+1。rest
一棵深度爲k且有2^k - 1個結點的二叉樹稱爲 滿二叉樹 。滿二叉樹的特色是每一層上的結點數都是最大結點數。
對滿二叉樹的結點進行連續編號,約定編號從根結點起,自上而下,自左至右。由此可引出徹底二叉樹的定義。深度爲k、有n個結點的二叉樹,當且僅當其每個結點都與深度爲k的滿二叉樹中編號從1~n的結點一一對應時,稱爲 徹底二叉樹 。如上圖所示徹底二叉樹具備的特色是:
(1)葉子結點只可能在層次最大的兩層上出現。
(2)對任一結點,若其右分支下的子孫的最大層次爲r,則其左分支下的子孫的最大層次必爲r或r+1。
用一組地址連續的存儲單元存儲二叉樹中的各個結點。爲了便於對二叉樹結點進行查找或處理,存儲時須要將普通二叉樹的各個結點按照它們在徹底二叉樹的對應結點位置依次存放到數組相應的存儲單元中。如圖所示,二又樹的順序存儲結構定義以下:
通常來講,順序存儲結構只適用於徹底二叉樹或滿二叉樹的存儲,由於普通二叉樹採用順序存儲結構進行存儲時,將致使存儲單元的浪費。最壞狀況下,對於一個深度爲k且只有k個結點的右支樹來講,存儲時須要2^k-1個存儲單元。
採用鏈式存儲結構存儲二叉樹時,能夠根據樹中的結點數動態申請所須要的結點,從而避免存儲空間的浪費。 由二叉樹的定義可知,每一個二叉樹的結點由一個數據元素和分別指向其左、右子樹的兩個分支組成。所以,定義二叉樹的結點結構時至少應包含三個域:數據域和左、右指針域。其中,數據域保存結點的信息左指針域存放指向其左子樹根的信息右指針域存放指向其右子樹根的信息,以下圖所示。有時,爲了便於找到結點的雙親,則可在上述結點結構中增長一個指向其雙親結點的指針域,以下圖所示。利用這兩種結點結構所得的二叉樹的存儲結構分別稱爲二又鏈表和三又鏈表。以下圖所示二叉樹的鏈式存儲結構。
二叉樹的遍歷 是指按照必定次序訪問樹中全部結點,而且每一個結點僅被訪問一次的過程。它是二叉樹最基本的運算,也是二叉樹中全部其餘運算的基礎。遍歷二叉樹的實質是對二叉樹的線性化過程,即遍歷的結果是將非線性結構的樹中結點排成一個線性序列,二叉樹的遍歷按訪問根結點的前後次序不一樣,可分爲 先序遍歷、中序遍歷 和 後序遍歷 。 下面對二叉樹的遍歷討論中,二叉樹都採用二叉鏈表的存儲結構。
根據二叉樹的遞歸特性,先序遍歷二叉樹的遞歸 過程以下: (1)訪問根結點。 (2)先序遍歷左子樹 (3)先序遍歷右子樹。
中序遍歷二叉樹的遞歸過程以下: (1)中序遍歷左子樹。 (2)訪問根結點。 (3)中序遍歷右子樹。
後序遍歷二叉樹的遞歸過程以下: (1)後序遍歷左子樹。 (2)後序遍歷右子樹。 (3)訪問根結點。
遍歷二又樹的算法中的基本操做是訪問結點,則不管按哪一種次序進行遍歷,對含有n個結點的二又樹,其時間複雜度均爲0(n)。所需輔助空間爲遍歷過程當中棧的最大容量,即樹的深度,最壞狀況下爲n,則空間複雜度也爲O(n)。
二叉樹的二叉鏈表表示法和樹的孩子兄弟表示法都是以二叉鏈表做爲存儲結構,結點的定義相同,只是解釋不一樣。所以,能夠找到樹和二又樹之間的對應關係,即給定一棵樹,能夠找到惟一的一棵二叉樹與之對應。
森林是樹的有限集合,能夠將森林當作一棵樹,其中全部樹的根結點彼此當作兄弟結點。這樣也能夠導出森林和二叉樹的對應關係。
下面給出森林和二叉樹相互轉換的遞歸定義:
一、森林轉換成二叉樹
若F={T1,T2,…,Tm}是森林(m≥0),則可按以下規則轉換成一棵二叉樹B=(root,LB,RB)。
(1)若m=0,則B爲空樹。
(2)若m>0,則B的根root即爲森林F中第一棵樹的根ROOT(T1);B的左子樹LB是從森林的第一棵樹T1中根結點的子樹森林F1={T1,T2,…,Tm}轉換而成的二叉樹;B的右子樹RB是從森林F中除T1外的剩餘部分F={T2,T3,…,Tm}轉換而成的二叉樹。
具體操做步驟以下:
(1)先將森林中的每一棵樹轉換爲二叉樹。
(2)按森林中樹的次序,依次將後一棵樹做爲前一棵樹的右子樹,並將第一棵樹的根做爲目標二又樹的根。
二、二叉樹轉換成森林
若是B=(roo,LB,RB)是一棵二叉樹,則可按以下規則轉換成森林F={T,,…,Tm}。
(1)若B爲空,則F爲空。
(2)若B非空,則F中第一棵樹T1的根ROOT(T1)即爲二叉樹B的根root;T1中根結點的子樹森林F1是由B的左子樹LB轉換而成的森林;F中除T1以外其他樹組成的森林F'={T2,T3,…,Tm}是由B的右子樹RB轉換而成的森林。
具體操做步驟以下:
(1)若二叉樹非空,則二叉樹根及其左子樹爲第一棵樹的二叉樹形式。
(2)二又樹根的右子樹又可看做是剩餘二叉樹構成的森林,再繼續分離出一棵樹,直至產生一顆沒有右子樹的二叉樹爲止。
注:文中的圖片均轉摘自網絡
若是須要跟我交流的話:
※ Github: github.com/wsl2ls
※ 簡書:www.jianshu.com/u/e15d1f644… ※ 微信公衆號:iOS2679114653 ※ QQ:1685527540