砍樹系列第一篇——樹
樹的本質
樹其實是一種非線性結構,我們熟知的線性結構,比如陣列,佇列,連結串列,構成線性結構的每個元素至多存在一個直接前驅(或直接後繼)元素。所謂非線性結構,是指在該結構中至少存在一個數據元素,有兩個或者兩個以上的直接前驅(或直接後繼)元素。天天走的大馬路,就是一種非線性結構。
樹的概念
樹的定義
樹是n(n≥0)個有限資料元素的集合。當n=0時,稱這棵樹為空樹。在一顆非空樹T中:
1)有一個特殊的資料元素成為樹的根節點,根節點是沒有前驅結點的。
2)若n>1,除根節點之外的其餘資料元素被分成m(m>0)個 互不相交(重點加粗) 的集合T1,T2,T3....Tm,其中每一個集合Ti(1≤ i ≤m)本身又是一棵樹,也都稱為這個根節點的子樹。
可以看出,在樹的定義中使用了遞迴概念,用樹來定義樹。

樹結構
從上述定義和上圖的示例,我們可以看出,樹具有下面兩個特點:
1)樹的根節點沒有前驅節點,除根節點之外的所有節點有且只有一個前驅節點。換句話來說,就是從根節點到子樹的某個節點,只能有一條 路徑(樹的術語,後續有解釋) 。
2)樹中所有節點可以有任意個後繼節點,當然也可以沒有。
根據上述特點可知下圖所示的就都不是樹結構。

非樹結構
樹的相關術語
1)結點
在樹中,一個元素也稱做一個結點。
2)結點的度
結點所擁有的子樹的個數稱為該結點的度。
3)葉結點
度為0的結點稱為葉結點,或者稱為終端結點(我覺得可以叫沒孩子的結點)。
4)分支結點
與葉結點相反,度不為0的結點稱為分支結點,或者稱為非終端結點。一棵樹的結點除葉結點外,其餘的都是分支結點。
5)孩子,雙親,兄弟
樹中一個結點的子樹的根節點稱為這個結點的孩子;反過來,這個結點稱為它孩子結點的雙親;具有同一個雙親的孩子結點互稱為兄弟。
6)路徑,路徑長度
如果一棵樹中的一串結點N1,N2,...,Nk有如下關係:結點Ni是Ni+1的父節點(1≤ i <k),就把N1,N2,...,Nk稱為一條由N1到Nk的路徑,這條路徑的長度就k-1。
7)祖先,子孫
在樹中,如果有一條路徑從結點M到結點N,那M就稱為N的祖先,而N稱為M的子孫。
8)結點的層數
規定樹的根節點的層數為1,其餘結點的層數等於它的雙親的結點的層數加1。
9)樹的深度
樹中結點的最大層數稱為樹的深度。
10)樹的度
樹中各結點度的最大值稱為該樹的度。
11)有序樹和無序樹
如果一棵樹中結點的各子樹從左到右是有次序的,那麼如果交換了某結點各子樹的相對位置,則會構成不同的樹,這樣的樹稱為有序樹;反之,則稱為無序樹。
12)森林
零棵或有限棵不相交的樹的集合稱為森林。自然界中樹和森林是不同的概念,但在資料結構中,樹和森林只有很小的區別。任何一棵樹,刪除根結點就變成了森林。
樹的表示
話不多說,直接上圖。

樹表示法
樹的基本操作
1)init(t):初始化一顆空樹t。
2)root(x):求結點x所在樹的根節點。
3)parent(t,x):求樹t中結點x是雙親結點。
4)child(t,x,i):求樹t中結點x的第i個孩子結點。
5)rightSibling(t,x):求樹t中結點x的第一個右邊兄弟結點。
6)insert(t,x,i,s):把以s為根結點的樹插入到樹t中作為結點x的第i棵子樹。
7)delete(t,x,i):在樹t中刪除結點x的第i棵子樹。
8)tranverse(t):樹的遍歷操作,即按某個方式訪問樹t中的每個結點,且使每個結點只被訪問一次。
樹的儲存
樹的儲存有多種方式,既可以採用順序儲存結構,也可以採用鏈式儲存結構,但無論採用哪種儲存方式,都要求儲存不但能夠儲存各結點本身的資料,還要能唯一地反映樹中各結點之間的邏輯關係,每種儲存方式都各有各的有點。常見的儲存方法有以下幾種。
1)雙親連結串列儲存方法
由樹的定義可以知道,樹中的每個節點都有唯一的一個雙親結點,根據這個特性,可以用一組連續的儲存空間儲存樹中的各個結點,每個節點除了存放本身的資訊外還有其雙親結點儲存位置,樹的這種儲存方法稱為雙親連結串列表示法,如下所示。

一棵樹及其雙親靜態連結串列儲存示意圖
當演算法中需要在樹結構中頻繁地查詢某結點的父結點或者根節點時,使用雙親表示法最合適。當頻繁地訪問結點的孩子結點時,雙親表示法就很麻煩,採用孩子連結串列表示法就很簡單。
2)孩子連結串列表示法
樹中每一個數據元素對應一個結點,結點中有兩部分資訊,一部分是其本身的資料資訊,另一部分是其孩子連結串列的頭指標,即將每個資料元素的孩子們連結成一個孩子連結串列,將連結串列的頭指標和它們的雙親資訊組成了一個結點,再將這些結點順序儲存起來。

一棵樹及其孩子連結串列儲存示意圖
在用孩子連結串列方法儲存的樹中,查詢雙親比較困難,查詢孩子卻十分方便,所以比較適用於對孩子操作多的應用。由於前兩種表示法都有侷限性,於是結合前兩種表示法,衍生出了雙親孩子連結串列表示法,優點不言而喻了,具體儲存方法如下圖所示。

一棵樹及其雙親孩子連結串列儲存示意圖
3)孩子兄弟連結串列儲存方法
這是一種常用的儲存結構。其方式是:在樹中每個元素對應一個結點,每個結點除其資訊域外,有兩個指標,分別指向該結點的第一個孩子結點和下一個兄弟結點。

一棵樹及其孩子兄弟連結串列儲存示意圖
仔細觀察不難發現,通過孩子兄弟連結串列儲存方法,普通樹轉化為了二叉樹,所以孩子兄弟表示法又被稱為“二叉樹表示法”或者“二叉連結串列表示法”。
樹的基本知識就介紹到這,下一篇將介紹樹和森林與二叉樹之間的轉換規則,樹和森林的遍歷方式,以及對應的演算法實現。