資料結構 - PowerPoint PPT Presentation

muriel
slide1 n.
Skip this Video
Loading SlideShow in 5 Seconds..
資料結構 PowerPoint Presentation
Download Presentation
資料結構

play fullscreen
1 / 48
Download Presentation
資料結構
74 Views
Download Presentation

資料結構

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. 資料結構 第6章 樹狀結構

  2. 6-1 認識樹 • 樹 (tree) 是由一或多個節點 所組成的有限集合,其特質如下: • 有一個特殊節點,稱為樹根 。 • 其餘節點可以分為n個互斥集合T1、T2、…、Tn (n ≥ 0),而且每個集合也都是一棵樹 。

  3. 6-1-1 樹的相關名詞 • 分支度 (degree) • 終端節點 (terminal node) • 非終端節點 (nonterminal node) • 階度 (level) • 父節點 (parent) • 子節點 (child) • 兄弟 (sibling) • 祖先 (ancestor) • 子孫 (descendant) • 高度 (height) 或深度 (depth) • 樹林 (forest)

  4. 6-1-2 樹的表示方式 • 我們可以使用串列表示樹,例如右圖的樹可以表示成(A(B(E, F(K)), C(G, H(L, M(N)), I), D(J))) • 至於每個節點在記憶體的儲存方式,我們可以使用如下的結構 :

  5. 6-2 二元樹 • 二元樹(binary tree) 是每個節點最多有兩個子節點的樹,節點的左邊稱為左子樹 ,節點的右邊稱為右子樹 。

  6. 範例6.2:證明二元樹第i階的最多節點個數為2i-1,i ≥ 1。 • 解答: • 當i = 1時,第1階最多只有樹根一個節點,故2i-1 = 21-1 = 20 = 1成立。 • 假設當1 ≤ i < k時,第i階的最多節點個數為2i-1成立,故第k - 1階的最多節點個數為2k-2。 • 證明當i = k時,第i階的最多節點個數為2i-1亦成立。由於第k - 1階的最多節點個數為2k-2,而二元樹的每個節點最多有兩個子節點,故第k階的最多節點個數為2k-2x 2 = 2k-1。

  7. 範例6.3:證明高度為h之二元樹的最多節點個數為2h - 1,h ≥ 1。 • 解答:由於二元樹第i階的最多節點個數為2i-1,因此,對高度為h的二元樹來說,全部存滿的話,總共有20 + 21 + … + 2h-1 = 2h - 1個節點。

  8. 6-2-1 完滿二元樹V.S. 完整二元樹 • 完滿二元樹 (full binary tree) • 完整二元樹 (complete binary tree)

  9. 假設完整二元樹的節點個數為n且節點依照0 ~ n - 1的順序編號,則其任意節點i (0 ≤ i ≤ n - 1) 具有下列特質: • 若i = 0,表示節點i為樹根,否則節點i的父節點為 (i - 1)/2 。 • 若2i + 1 ≥ n,表示節點i沒有左子節點,否則節點i的左子節點為2i + 1。 • 若2i + 2 ≥ n,表示節點i沒有右子節點,否則節點i的右子節點為2i + 2。

  10. 範例6.6:證明節點個數為n之完整二元樹的高度為 log2n + 1。

  11. 6-2-2 二元樹的表示方式 • 使用陣列實作二元樹

  12. 使用鏈結串列實作二元樹 typedef struct node{ struct node *lchild; char data; struct node *rchild; }tree_node; typedef tree_node *tree_pointer;

  13. 6-2-3 將一般樹轉換為二元樹 • 範例6.7:將下面的一般樹轉換為二元樹。

  14. 6-3 二元樹的走訪 6-3-1 中序走訪 inorder(tree_pointer root) { if (root){ inorder(root->lchild); printf("%d ", root->data); inorder(root->rchild); } } 右圖的中序走訪的結果為DBGEHACFI。

  15. 6-3-2 前序走訪 preorder(tree_pointer root) { if (root){ printf("%d ", root->data); preorder(root->lchild); preorder(root->rchild); } } 右圖的前序走訪的結果為ABDEGHCFI。

  16. 6-3-3 後序走訪 postorder(tree_pointer root) { if (root){ postorder(root->lchild); postorder(root->rchild); printf("%d", root->data); } } 右圖的後序走訪的結果為DGHEBIFCA。

  17. 6-3-4 決定唯一的二元樹 • 範例6.11:[決定唯一的二元樹] 假設二元樹的中序與前序走訪分別為DBEACGFH、ABDECFGH,試據此推算出該二元樹。

  18. 6-4 二元樹的其它運算 6-4-1 複製二元樹 範例6.13:撰寫一個函數實作複製二元樹運算。 tree_pointer copy(tree_pointer source) { tree_pointer destination; if (source){ destination = (tree_pointer)malloc(sizeof(tree_node)); destination->lchild = copy(source->lchild); destination->rchild = copy(source->rchild); destination->data = source->data; return destination; } return NULL; }

  19. 6-4-2 比較二元樹 範例6.14:撰寫一個函數實作比較二元樹運算。 int equal(tree_pointer source, tree_pointer destination) { if ((!source && !destination) || (source && destination && (source->data == destination->data) && equal(source->lchild, destination->lchild) && equal(source->rchild, destination->rchild)) return 1; else return 0; }

  20. 6-5 運算式樹 • 運算式樹 (expression tree) 指的是滿足下列條件的二元樹: • 終端節點為運算元 (operand),而非終端節點為運算子 (operator)。 • 子樹為子運算式且其樹根為運算子。

  21. 6-6 引線二元樹 • 引線二元樹 (threaded binary tree) 的左引線 (left thread) 指向節點本身的中序前行者 (inorder predecessor),右引線 (left thread) 指向節點本身的中序後繼者 (inorder successor) 。

  22. 6-6-1 節點結構 #define THRAED 1 #define POINTER 0 typedef struct thnode{ int lthread; struct threaded_node *lchild; char data; struct threaded_node *rchild; int rthread; }threaded_node; typedef threaded_node *threaded_pointer;

  23. 空的引線二元樹 (只有包含首節點) 加入首節點的引線二元樹

  24. 6-6-2 中序走訪 • 範例6.15:撰寫一個函數在引線二元樹中找出任意節點的中序後繼者。 threaded_pointer inorder_successor(threaded_pointer ptr) { threaded_pointer tmp; tmp = ptr->rchild; if (tmp == POINTER) while(tmp->lchild == POINTER) tmp = tmp->lchild; return tmp; }

  25. 範例6.16:利用範例6.15所撰寫的inorder_successor() 函數完成引線二元樹的中序走訪。 threaded_inorder (threaded_pointer head) { threaded_pointer tmp; for(;;){ tmp = inorder_successor(tmp); if (tmp == head) break; printf("%d ", tmp->data); } }

  26. 6-6-3 插入節點 • 情況一: • 將新節點T插入節點S的右兒子且新節點T是樹葉

  27. threaded_pointer tmp; T->rthread = S->rthread; T->rchild = S->rchild; T->lthread = THREAD; T->lchild = S; S->rthread = POINTER; S-rchild = T; if (T->rthread == POINTER){ tmp = T->rchild; while(tmp->lchild == POINTER) tmp = tmp->lchild; tmp->lchild = T; } (1) (2) (3) (4) • 將新節點T插入節點S的右兒子且新節點T不是樹葉

  28. 情況二: • 將新節點T插入節點S的左兒子且新節點T是樹葉

  29. T->lthread = S->lthread; T->lchild = S->lchild; T->rthread = THREAD; T->rchild = S; S->lthread = POINTER; S-lchild = T; if (T->lthread == POINTER){ tmp = T->lchild; while(tmp->rchild == POINTER) tmp = tmp->rchild; tmp->rchild = T; } (1) (2) (3) (4) • 將新節點T插入節點S的左兒子且新節點T不是樹葉

  30. 6-7 二元搜尋樹 • 二元搜尋樹是滿足下列條件的二元樹: • 每個節點包含唯一的鍵值 (key)。 • 左右子樹亦為二元搜尋樹。 • 左子樹的鍵值必須小於其樹根的鍵值 • 右子樹的鍵值必須大於其樹根的鍵值。

  31. 6-7-1 搜尋節點 • 先和樹根做比較,若指定的鍵值小於樹根,就以同樣的方式搜尋樹根的左子樹,若指定的鍵值大於樹根,就以同樣的方式搜尋樹根的右子樹,左右子樹均據此定義遞迴地搜尋下去。 • 寫出在右圖的二元搜尋樹搜尋70和35兩個鍵值的過程。

  32. 範例6.20:以遞迴的方式撰寫一個函數在二元搜尋樹搜尋節點。範例6.20:以遞迴的方式撰寫一個函數在二元搜尋樹搜尋節點。 tree_pointer search2(tree_pointer root, int key) { if (!root) return NULL; if (key == root->data) return root; if (key < root->data) return search2(root->lchild, key); else return search2(root->rchild, key); }

  33. 6-7-2 插入節點 • 先和樹根做比較,若新節點小於樹根,就以同樣的方式移往樹根的左子樹,若新節點大於樹根,就以同樣的方式移往樹根的右子樹,直到抵達子樹的尾端,再將新節點加入子樹的尾端。

  34. 範例6.21:[建構二元搜尋樹] 將數字串列 (25, 30, 24, 58, 45, 26, 12, 14) 建構為二元搜尋樹。

  35. 假設將數字串列 (25, 30, 24, 58, 45, 26, 12, 14) 變更為 (25, 30, 24, 58, 45, 26, 14, 12),後面兩個資料的順序交換,則建構出來的二元搜尋樹如下:

  36. 假設將數字串列 (25, 30, 24, 58, 45, 26, 12, 14) 變更為 (12, 14, 24, 25, 26, 30, 45, 58),資料由小到大排序,則建構出來的二元搜尋樹如下:

  37. 6-7-3 刪除節點 • 情況一:當欲刪除的節點是樹葉時,直接刪除該節點即可。

  38. 情況二:當欲刪除的節點有一棵子樹時,將其父節點的指標改指向其子節點,然後刪除該節點即可。

  39. 情況三:當欲刪除的節點有兩棵子樹時,以該節點的左子樹中最大節點或右子樹中最小節點填入其位置,然後刪除該節點即可。

  40. 6-8 霍夫曼樹 • 範例6.23:[建構霍夫曼樹] 假設A、B、C、D、E、F等六個符號的出現頻率為0.2、0.15、0.3、0.18、0.05、0.12,試據此建構霍夫曼樹並寫出各個符號的編碼。

  41. 範例6.24:[霍夫曼碼解碼] 根據範例6.23所設計的霍夫曼碼,將111110010000110進行解碼。 • 解答:由於A、B、C、D、E、F等六個符號分別被編碼為01、110、10、00、1110、1111,故將111110010000110解碼後會得到FCADDB。

  42. 6-9 樹林 • 樹林 (forest) 是由n棵互斥樹所組成的集合 (n ≥ 0),適合用來表示互斥集合 (disjoin set)。 樹去掉樹根後就會得到樹林 樹

  43. 範例6.26:將下面的樹林轉換為二元樹。

  44. 6-10 集合 • 集合 (set) 是一群相同類型、沒有順序之分的元素,而互斥集合 (disjoin set) 是沒有相同元素的集合 。

  45. 互斥集合常見的運算有下列兩種: • 聯集 (union) • 搜尋 (find) (a) S1 U S2 (b) S2 U S1

  46. 使用陣列存放互斥集合,以下圖的S1、S2、S3等三個集合為例,陣列的內容如下,

  47. 互斥集合的聯集運算函數 set_union(int i, int j) { parent[i] = j; } • 呼叫聯集運算函數建立S1、S2、S3等三個集合和S1∪S2集合: set_union(0, 2); set_union(1, 2); set_union(3, 4); set_union(5, 8); set_union(6, 8); set_union(7, 8); set_union(4, 2);

  48. 互斥集合的搜尋運算函數 int find(int i) { while(parent[i] > 0 i = parent[i]; return i; }