1749 views
# Tree 樹 ## 定義 (1)任兩點之間有一個路徑可以相通,且沒有"環"結構的圖。也可以看做是由一個點開始,藉由很多條邊向外拓展到其他點上,而且點和邊都沒有被重複拓展到。 (2)是由≧1個node所形成的集合,==不可以為空==,並且滿足以下條件: a.至少有一個特殊的node,稱為root。 b.其餘node分成 $T_1,T_2,...T_n$之互斥集合,而$T_1~T_n$稱為root的子樹(subtrees)。 * **環 (cycle)** : 沿著邊的排列走,可以走到起點的圖。 ```graphviz graph graphname{ a--b; a--c; b--d; b--e; c--f; c--g; } ``` ## 名詞定義 * **節點 (node)** : 進行延伸拓展的點、被延伸拓展到的點,也就是說樹上的點都是「節點」。每個節點包括一項資料以及指向其他節點的分枝。 * **分支 (branch)** : 兩個節點之間的連線或指標,分枝所連接的兩個節點具有父子關係。 ```graphviz graph graphname{ a [label="node" ; fontcolor=blue ; color = blue ] b [label="node" ; fontcolor=blue ; color = blue ] c [label="node" ; fontcolor=blue ; color = blue ] a -- b [color=red]; a -- c [label="branch" ; color=red ; fontcolor=red]; } ``` * **樹根 (root)** : 一棵樹可以想作是由一個點開始分枝所形成,而這個點即為樹根。一棵樹上的每個點都可以當作樹根。 * **樹葉 (leaf)** : 在一棵樹上選定一個根之後,由根開始不斷分枝,途中無法繼續分枝的點即為樹葉。也可以不選定根,這種情況下,只連著一條邊的點都是「葉」。如果樹上總共只有一個點,那麼此點既是根、也是葉。又可稱為 **「終端節點 (terminal node)」** 或 **「外部節點 (externel node)」**。 ```graphviz digraph graphname{ a[label="root" ; color=brown ; fontcolor = brown] d[label="leaf" ; color=green ; fontcolor = green] e[label="leaf" ; color=green ; fontcolor = green] f[label="leaf" ; color=green ; fontcolor = green] g[label="leaf" ; color=green ; fontcolor = green] h[label="leaf" ; color=green ; fontcolor = green] b[label=" "] c[label=" "] a->b; a->h; a->c; b->d; b->e; c->f; c->g; {rank=same;a,c} } ``` * **階層 (level)** : 在一棵樹上選定根後,按照拓展的順序(也就是按照每個點離根的距離),將樹上的點分層次,使得樹上每一個點都擁有一個層數。如果改變根,那麼分層的結果就會不同。 * **父親(parent)** 與 **小孩(child)** : 。在一棵樹上選定根後,以邊相連的任兩點,靠近樹根者相對地稱作「父親」,靠近樹葉者相對地稱作「小孩」。父親只有一個,特例是:是樹根沒有父親;小孩可以很多個,特例是:樹葉沒有小孩。 * **樹的分支度(degree)** :一棵樹中所有節點支度最大者,又稱作 **「樹的階度 (order)」**。若一棵樹的order為k,則在樹中節點的最大分支度為k。 * **祖先(ancestor)** 和 **子孫(descendant)** : 在一棵樹上選定根後,一個點的父親、父親的父親等等,皆是此點的「祖先」。一個點的小孩、小孩的小孩等等,皆是此點的「子孫」。 * **高度(height)** : 樹中節點的最大階層,又可稱為 **「深度(depth)」** 。 * **森林(forest)** : 由很多棵樹所形成的集合稱作森林。只有一棵樹也可以稱作森林。 ## Tree的表示方式(PDF p.83) ### 方法一 : 利用Linked List 直接表示 * 作法 : **假設Tree的degree為k** 則每個節點的structure為 ```graphviz digraph structs{ node[shape=record] struct1[label="<f0>Data|<f1>Link_1|<f2>Link_2|<f3>........|<f4>Link_k"] struct2[label="<f0>Data|<f1>Link_1|<f2>Link_2|<f3>........|<f4>Link_k"; color=white ; fontcolor = white] struct1:f1->struct2:f1; struct1:f2->struct2:f2[label=" 共有k條Link欄"]; struct1:f4->struct2:f4; } ``` * 範例 : ```graphviz graph{ A--B; A--C; A--D; C--E; C--F; } ``` ```graphviz digraph structs{ node[shape=record] A[label="<f0>A|<f1>Link_1|<f2>Link_2|<f3>Link_3"] B[label="<f0>B|<f1>Link_1|<f2>Link_2|<f3>Link_3"] C[label="<f0>C|<f1>Link_1|<f2>Link_2|<f3>Link_3"] D[label="<f0>D|<f1>Link_1|<f2>Link_2|<f3>Link_3"] E[label="<f0>E|<f1>Link_1|<f2>Link_2|<f3>Link_3"] F[label="<f0>F|<f1>Link_1|<f2>Link_2|<f3>Link_3"] A:f1->B:f0 A:f2->C:f0 A:f3->D:f0 C:f1->E:f0 C:f2->F:f0 {rank=same;B,C,D} } ``` * 分析 : 最大缺點在於極度浪費linking space。 說明: ==假設有**n**個node==,==Tree的degree為**k**==,則 link 總共有 **n×k** 條,其中==有用的==有**n-1**條 $\Rightarrow$浪費比例 $$ \frac{nk-(n-1)}{nk}=\frac{n(k-1)+1}{nk}\cong\frac{n(k-1)}{nk}=\frac{k-1}{k} $$ (k=2時會最少) ### 方法二 : 括號法 * 以 ==父(子1,子2,.......,子k)== 括號的方式來表達父點和的子點的關係。 * 範例 : **A(BC(EF)D)** ```graphviz graph{ A--B; A--C; A--D; C--E; C--F; } ``` ### 方法三 : "Child-Sibling"方法(左子右弟法) * 做法 : **Node** ```graphviz digraph struct{ node[shape=record] a[label="<1>Data|<2>child|<3>siblig"] } ``` **child** : 將 pointer 指向第一個(最左邊)的 child (若無 child,則為 NULL )。 **sibling** : 將 pointer 指向其右鄰兄弟。 * 範例 : ```graphviz graph{ A--B; A--C; A--D; C--E; C--F; } ``` ```graphviz digraph struct{ rankdir="LR" splines="line" nodesep=0.5 node[shape=record] A[label="{<1>A|<2>|<3>NULL}"] B[label="{<1>B|<2>NULL|<3>}"] C[label="{<1>C|<2>|<3>}"] D[label="{<1>D|<2>|<3>NULL}"] E[label="{<1>E|<2>NULL|<3>}"] F[label="{<1>F|<2>|<3>NULL}"] B:1->A:2[dir="back";color=red;label="child"] A->C[color =white] B->C[color=blue;label="sibling"] B->E[color =white] E:1->C:2[dir="back";color=red;label="child"] C->D[color=blue;label="sibling"] C->F[color =white] E->F[color=blue;label="sibling"] } ``` ### 方法四 : 將tree化成binary tree之後再表示 (見binary tree)