--- tags: 圖論 title: 基礎樹論 --- :::info #### 本頁題目整理 1. [樹走訪 練習題](https://zerojudge.tw/ShowProblem?problemid=c463) 2. [BST 模板題](https://zerojudge.tw/ShowProblem?problemid=d526) 3. [Heap 模板題](https://zerojudge.tw/ShowProblem?problemid=a091) 4. [Heap Swap 練習題](https://www.luogu.com.cn/problem/T136291?contestId=38025) 5. [樹直徑 模板題](https://tioj.ck.tp.edu.tw/problems/1213) ::: # 樹 *以下複雜度的$V$皆為樹的節點數量* - 樹的名詞 ![](https://i.imgur.com/6mtYxdW.png) - 樹的儲存: - 鄰接矩陣(Adjacency matrix) - 走訪時間:$O(V^2)$ - 空間:$O(V^2)$ - 鄰接串列(Adjacency list) - 走訪時間:$O(V)$ - 空間:$O(V)$ - 樹走訪:大多使用DFS走訪 - [樹走訪 模板題](https://zerojudge.tw/ShowProblem?problemid=c463) ## 二元樹 - 就是每個母節點有兩個子節點的樹 - 複雜度常常跟$log_{(2)} N$有關 ### 二元搜尋樹(BST) - 左子節點 < 母節點 < 右子節點 - 常見操作: - 插入 - 時間:$O(logV)$、$T(V)$ - 查詢某數存在與否 - 時間:$O(logV)$、$T(V)$ - 刪除 - 時間:$O(logV)$、$T(V)$ - 空間:$O(V)$ :::success #### BST struct ```cpp= struct Node{ Data key; Node *left, *right; Node(Data _key) { left = right = nullptr; key = _key; } }; ``` ::: :::success #### 插入 ```cpp= Node* insert(struct Node* node, int key) { if (node == NULL) return new Node(key); if (key < node->key) node->left = insert(node->left, key); else node->right = insert(node->right, key); return node; } ``` ::: :::success ### 刪除 - 刪除時我們分為幾種狀況來討論: 1. 刪除的點在樹葉(也就是沒有子樹)。 2. 刪除的點只有一個子樹。 3. 刪除的點有兩個子樹。 **1. 當刪除的點是樹葉時,我們直接刪除即可:** ![](https://i.imgur.com/C3eIbR3.png) ```cpp= if(node->leftNode == NULL && node->rightNode == NULL) { delete node; node = NULL; } ``` **2. 當刪除的點只有一個子樹,我們將該子樹替換成自己:** ![](https://i.imgur.com/Xxs3Y1V.png) ```cpp= else if(node->leftNode == NULL) node->rightNode = node; else if(n->rightNode == NULL) node->leftNode = node; ``` **3. 當刪除的點有兩個子樹的情形最複雜,我們有兩種做法:** ![](https://i.imgur.com/Rm0zn0a.png) - 將自己刪除後,找左子樹最大來替補自己: ```cpp= else { Data leftMax = FindMax(node->leftNode); node->data = leftMax; Delete(node->leftNode, leftMax); } ``` - 或是找右子樹最小替補: ```cpp= else { Data rightMin = FindMin(node->rightNode); node->data = rightMin; Delete(node->rightNode, rightMin); } ``` ### 最後統整一下,整個刪除應為: ```cpp= void Delete(Data d, Node* node) { if(node == NULL) return; if(node->data == d) { if(node->leftNode == NULL && node->rightNode == NULL) { delete node; node = NULL; } else if(node->leftNode == NULL) node->rightNode = node; else if(node->rightNode == NULL) node->leftNode = node; else { Data leftMax = FindMax(node->leftNode); node->data = leftMax; Delete(node->leftNode, leftMax); } } else if(node->data < d) Delete(d, node->leftNode); else Delete(d, node->rightNode); } ``` ::: - [BST 模板題](https://zerojudge.tw/ShowProblem?problemid=d526) ### 堆(Heap) - 左子節、右子節點 < 母節點 - 常見操作: - 插入 - 時間:$O(logV)$ - 查詢最大/最小值 - 時間:$O(1)$ - 刪除 - 時間:$O(logV)$ - 空間:$O(V)$ - [Heap 模板題](https://zerojudge.tw/ShowProblem?problemid=a091) - [Heap Swap 練習題](https://www.luogu.com.cn/problem/T136291?contestId=38025) ## 樹直徑 - 樹上最長鍊ㄅ - 時間:$O(V)$ - 空間:$O(V)$ - [樹直徑 模板題](https://tioj.ck.tp.edu.tw/problems/1213) :::info #### 小提示:題目分類方法 1. 模板題:直接刻一次算法就好的題目,難度為算法本身自帶的難度 2. 練習題:帶上算法概念的題目,難度偏易 4. 變形題:如果不告訴你算法你不容易看出來的,難度中等 5. 挑戰題:需要綜合其他算法來思考題目,難度較高 6. 瘋癲題:如果前面題目都覺得太簡單,不妨試試這個,難度升天 :::