樹的遍歷
重建樹
根據給定原始樹的先序遍歷 (preorder traversal) 和中序遍歷 (inorder traversal)重構原始樹。
前序遍歷的順序為 [根結點、左子樹、右子樹],而中序遍歷的順序為 [左子樹、根結點、右子樹],因此我們可以透過前序遍歷的第一個元素找到根結點,將其帶入中序遍歷,就可以找到左、右子樹,對左、右子樹遞迴進行此行為就可以構造出原始樹,
函式程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 TreeNode* BuildTree (string preord, string inord, int preord_left, int preord_right, int inord_left, int inord_right) { if (preord_left > preord_right) { return NULL ; } int preord_root = preord_left; int inord_root = inord.find (preord[preord_root]); TreeNode* root = new TreeNode (preord[preord_root]); int size_left_subtree = inord_root - inord_left; root->leftChild = BuildTree (preord, inord, preord_left + 1 , preord_left + size_left_subtree, inord_left, inord_root - 1 ); root->rightChild = BuildTree (preord, inord, preord_left + size_left_subtree + 1 , preord_right, inord_root + 1 , inord_right); return root; }
二元搜尋樹
給定一棵二元搜尋樹 (binary search tree) 的先序遍歷 (preorder traversal),重構出原始樹。
二元搜尋樹的特性:
一個節點的左子樹只包含鍵值小於該節點的節點。
一個節點的右子樹只包含鍵值大於該節點的節點。
左子樹和右子樹也都是二分搜尋樹。
因為有以上特性,在區分左、右子樹時不需要利用到原始樹的中序遍歷,只要在前序遍歷中找到鍵值大於根結點的地方就是右子樹了,之後也是利用遞迴的方式建構出原始樹。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 TreeNode* BuildTree (int preord[], int left, int right) { if (left > right) { return NULL ; } int preord_root = left; int size_left_subtree = 0 ; for (int i = left+1 ; i <= right; i++){ if (preord[i] > preord[preord_root]) break ; size_left_subtree++; } TreeNode* root = new TreeNode (preord[preord_root]); root->leftChild = BuildTree (preord, left + 1 , left + size_left_subtree); root->rightChild = BuildTree (preord, left + size_left_subtree + 1 , right); return root; }
最小生成樹
Prim’s algorithm
設定初始節點,將其加入最小生成樹中。
在包含已選中與未選中的邊 (一端選中一端未選中) 中尋找權重最小者,將其加入最小生成樹中。
重複步驟 2 直到所有點都在最小生成樹內。
Kruskal’s algorithm
將所有邊依照權重由小排到大。
選擇權重最小邊,加入最小生成樹中。
檢查最小生成樹是否形成 circle,如果有則刪除剛剛加入的邊。
重複步驟 2 3 直到所有邊都考慮完畢。
Sollin’s algorithm
把每個點都當成一棵樹。
在所有樹中挑選出權重最小的邊。
如果有重複的邊只要保留一個,並且將選中的邊加入最小生成樹。
重複步驟 2 3 直到只剩下一顆樹 or 所有邊都已考慮完畢。