시리즈: Algorithms
cpp
480 줄
· 업데이트 2026-03-28
tree_bst.cpp
Algorithms/tree_bst.cpp
/*
* ============================================================================
* Binary Search Tree (BST) — 完整實作
* File: tree_bst.cpp
*
* BST 性質:左子樹所有值 < root < 右子樹所有值
*
* 涵蓋操作:
* 1. Insert(插入)
* 2. Search / Contains(搜尋)
* 3. FindMin / FindMax
* 4. Delete(刪除)— 三種情況
* 5. Inorder Traversal(中序遍歷 → 排序輸出)
* 6. Preorder / Postorder Traversal
* 7. Level-order Traversal(BFS)
* 8. Height / Size / IsBalanced
* 9. 由 Preorder + Inorder 重建二元樹
* 10. 印出樹的結構
*
* Compile: g++ -std=c++11 -Wall -o tree_bst tree_bst.cpp
* ============================================================================
*/
#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
using namespace std;
/* ============================================================================
* 節點結構
* ============================================================================ */
struct BSTNode {
int data;
BSTNode* left;
BSTNode* right;
BSTNode(int val) : data(val), left(nullptr), right(nullptr) {}
};
/* ============================================================================
* 1. Insert(插入)
*
* 遞迴地找到正確位置,新節點一定插入為 leaf。
* - 如果 key < node->data → 往左走
* - 如果 key > node->data → 往右走
* - 如果 key == node->data → 不插入(不允許重複)
*
* 時間:平均 O(log N),最壞 O(N)(退化成 linked list)
* ============================================================================ */
BSTNode* insert(BSTNode* node, int key) {
// 找到空位置 → 建立新節點
if (node == nullptr) {
return new BSTNode(key);
}
if (key < node->data) {
// key 比當前節點小 → 插入左子樹
node->left = insert(node->left, key);
} else if (key > node->data) {
// key 比當前節點大 → 插入右子樹
node->right = insert(node->right, key);
}
// key == node->data → 已存在,不插入
return node;
}
/* ============================================================================
* 2. Search / Contains(搜尋)
*
* 類似 binary search:
* - 比當前小 → 往左找
* - 比當前大 → 往右找
* - 相等 → 找到了
*
* 時間:平均 O(log N),最壞 O(N)
* ============================================================================ */
BSTNode* search(BSTNode* node, int key) {
if (node == nullptr) return nullptr; // 沒找到
if (key == node->data) return node; // 找到了
if (key < node->data) return search(node->left, key); // 往左
return search(node->right, key); // 往右
}
// 回傳 bool 的版本
bool contains(BSTNode* node, int key) {
return search(node, key) != nullptr;
}
/* ============================================================================
* 3. FindMin / FindMax
*
* FindMin: BST 中最小值 = 一路往左走到底
* FindMax: BST 中最大值 = 一路往右走到底
*
* 時間:O(h),h = 樹的高度
* ============================================================================ */
BSTNode* findMin(BSTNode* node) {
if (node == nullptr) return nullptr;
// 一路往左走到底
while (node->left != nullptr) {
node = node->left;
}
return node;
}
BSTNode* findMax(BSTNode* node) {
if (node == nullptr) return nullptr;
// 一路往右走到底
while (node->right != nullptr) {
node = node->right;
}
return node;
}
/* ============================================================================
* 4. Delete(刪除)— 三種情況
*
* Case 1: 要刪除的節點是 leaf(無子節點)→ 直接移除
* Case 2: 要刪除的節點有一個 child → 用 child 取代自己
* Case 3: 要刪除的節點有兩個 children →
* 找中序後繼(右子樹的最小值),用其值取代自己,
* 再遞迴刪除右子樹中的那個後繼節點
*
* 時間:平均 O(log N),最壞 O(N)
* ============================================================================ */
BSTNode* deleteNode(BSTNode* node, int key) {
if (node == nullptr) return nullptr; // 沒找到要刪的節點
if (key < node->data) {
// 要刪的在左子樹
node->left = deleteNode(node->left, key);
} else if (key > node->data) {
// 要刪的在右子樹
node->right = deleteNode(node->right, key);
} else {
// 找到了!node->data == key
// Case 1 & 2: 沒有左子 或 沒有右子(包含 leaf 的情況)
if (node->left == nullptr) {
BSTNode* rightChild = node->right;
delete node;
return rightChild; // 可能是 nullptr (leaf case)
}
if (node->right == nullptr) {
BSTNode* leftChild = node->left;
delete node;
return leftChild;
}
// Case 3: 有兩個 children
// 找右子樹的最小值(中序後繼)
BSTNode* successor = findMin(node->right);
// 用後繼的值取代自己
node->data = successor->data;
// 遞迴刪除右子樹中的那個後繼(它最多只有一個 right child)
node->right = deleteNode(node->right, successor->data);
}
return node;
}
/* ============================================================================
* 5. Inorder Traversal(中序遍歷)
*
* 順序:Left → Root → Right
* 對 BST 來說,inorder 輸出的是排序後的遞增序列。
* ============================================================================ */
void inorder(BSTNode* node) {
if (node == nullptr) return;
inorder(node->left); // 先走左子樹
cout << node->data << " "; // 訪問自己
inorder(node->right); // 再走右子樹
}
// 把 inorder 結果存到 vector
void inorderToVector(BSTNode* node, vector<int>& result) {
if (node == nullptr) return;
inorderToVector(node->left, result);
result.push_back(node->data);
inorderToVector(node->right, result);
}
/* ============================================================================
* 6. Preorder / Postorder Traversal
* ============================================================================ */
void preorder(BSTNode* node) {
if (node == nullptr) return;
cout << node->data << " "; // Root
preorder(node->left); // Left
preorder(node->right); // Right
}
void postorder(BSTNode* node) {
if (node == nullptr) return;
postorder(node->left); // Left
postorder(node->right); // Right
cout << node->data << " "; // Root
}
/* ============================================================================
* 7. Level-order Traversal(BFS 層序遍歷)
*
* 使用 Queue,逐層由左到右輸出。
* ============================================================================ */
void levelOrder(BSTNode* root) {
if (root == nullptr) return;
queue<BSTNode*> q;
q.push(root);
while (!q.empty()) {
// 每次處理一層
int levelSize = (int)q.size();
for (int i = 0; i < levelSize; ++i) {
BSTNode* cur = q.front();
q.pop();
cout << cur->data << " ";
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
}
cout << "| "; // 層與層之間的分隔
}
cout << endl;
}
/* ============================================================================
* 8. Height / Size / IsBalanced
* ============================================================================ */
// 高度:空樹 = -1,只有 root = 0
int height(BSTNode* node) {
if (node == nullptr) return -1;
return 1 + max(height(node->left), height(node->right));
}
// 節點總數
int size(BSTNode* node) {
if (node == nullptr) return 0;
return 1 + size(node->left) + size(node->right);
}
// 檢查是否為平衡二元樹(每個節點的左右高度差 ≤ 1)
// 回傳 -1 表示不平衡,否則回傳高度
int checkBalance(BSTNode* node) {
if (node == nullptr) return 0;
int leftH = checkBalance(node->left);
if (leftH == -1) return -1; // 左子樹已不平衡
int rightH = checkBalance(node->right);
if (rightH == -1) return -1; // 右子樹已不平衡
if (abs(leftH - rightH) > 1) return -1; // 當前節點不平衡
return 1 + max(leftH, rightH);
}
bool isBalanced(BSTNode* root) {
return checkBalance(root) != -1;
}
/* ============================================================================
* 9. 由 Preorder + Inorder 重建二元樹
*
* 原理:
* - Preorder 的第一個元素 = root
* - 在 Inorder 中找到 root → 左邊 = 左子樹,右邊 = 右子樹
* - 遞迴處理
* ============================================================================ */
BSTNode* buildTree(const vector<int>& preorder, int preStart, int preEnd,
const vector<int>& inorder, int inStart, int inEnd) {
if (preStart > preEnd || inStart > inEnd) return nullptr;
// Preorder 的第一個元素 = 當前子樹的 root
int rootVal = preorder[preStart];
BSTNode* root = new BSTNode(rootVal);
// 在 Inorder 中找到 root 的位置
int rootIdx = inStart;
while (rootIdx <= inEnd && inorder[rootIdx] != rootVal) {
++rootIdx;
}
// 左子樹的節點數
int leftSize = rootIdx - inStart;
// 遞迴建立左子樹和右子樹
root->left = buildTree(preorder, preStart + 1, preStart + leftSize,
inorder, inStart, rootIdx - 1);
root->right = buildTree(preorder, preStart + leftSize + 1, preEnd,
inorder, rootIdx + 1, inEnd);
return root;
}
/* ============================================================================
* 10. 印出樹的結構(ASCII 視覺化)
* ============================================================================ */
void printTree(BSTNode* node, const string& prefix = "", bool isLeft = true) {
if (node == nullptr) return;
// 先印右子樹(在上方)
if (node->right) {
printTree(node->right, prefix + (isLeft ? "│ " : " "), false);
}
// 印自己
cout << prefix;
cout << (isLeft ? "└── " : "┌── ");
cout << node->data << endl;
// 再印左子樹(在下方)
if (node->left) {
printTree(node->left, prefix + (isLeft ? " " : "│ "), true);
}
}
/* ============================================================================
* 釋放記憶體
* ============================================================================ */
void deleteTree(BSTNode* node) {
if (node == nullptr) return;
deleteTree(node->left);
deleteTree(node->right);
delete node;
}
/* ============================================================================
* 主程式
* ============================================================================ */
int main() {
cout << "============================================" << endl;
cout << " Binary Search Tree (BST) Complete Demo" << endl;
cout << "============================================\n" << endl;
BSTNode* root = nullptr;
// ── 插入 ──
cout << "--- Insert: 50, 30, 70, 20, 40, 60, 80, 10, 25, 35, 45 ---\n" << endl;
int keys[] = {50, 30, 70, 20, 40, 60, 80, 10, 25, 35, 45};
for (int k : keys) {
root = insert(root, k);
}
/*
* 建構出的 BST:
*
* 50
* / \
* 30 70
* / \ / \
* 20 40 60 80
* / \ / \
* 10 25 35 45
*/
cout << "Tree structure:" << endl;
printTree(root);
cout << endl;
// ── 遍歷 ──
cout << "--- Traversals ---\n" << endl;
cout << "Inorder (sorted): ";
inorder(root);
cout << endl;
cout << "Preorder: ";
preorder(root);
cout << endl;
cout << "Postorder: ";
postorder(root);
cout << endl;
cout << "Level-order: ";
levelOrder(root);
cout << endl;
// ── 搜尋 ──
cout << "--- Search ---\n" << endl;
cout << "contains(40) = " << (contains(root, 40) ? "true" : "false") << endl;
cout << "contains(99) = " << (contains(root, 99) ? "true" : "false") << endl;
cout << endl;
// ── FindMin / FindMax ──
cout << "--- FindMin / FindMax ---\n" << endl;
cout << "Min = " << findMin(root)->data << endl;
cout << "Max = " << findMax(root)->data << endl;
cout << endl;
// ── 統計 ──
cout << "--- Statistics ---\n" << endl;
cout << "Height: " << height(root) << endl;
cout << "Size: " << size(root) << endl;
cout << "IsBalanced: " << (isBalanced(root) ? "true" : "false") << endl;
cout << endl;
// ── 刪除 ──
cout << "--- Delete ---\n" << endl;
// Case 1: 刪除 leaf (10)
cout << "Delete 10 (leaf):" << endl;
root = deleteNode(root, 10);
printTree(root);
cout << endl;
// Case 2: 刪除有一個 child 的節點 (20, 只有 right child 25)
cout << "Delete 20 (one child):" << endl;
root = deleteNode(root, 20);
printTree(root);
cout << endl;
// Case 3: 刪除有兩個 children 的節點 (30)
cout << "Delete 30 (two children):" << endl;
root = deleteNode(root, 30);
printTree(root);
cout << endl;
cout << "Inorder after deletions: ";
inorder(root);
cout << endl;
cout << endl;
// ── 退化情況示範 ──
cout << "--- Skewed BST (degenerate case) ---\n" << endl;
BSTNode* skewed = nullptr;
// 按順序插入 → 退化成 linked list
for (int i = 1; i <= 5; ++i) {
skewed = insert(skewed, i);
}
cout << "Insert 1,2,3,4,5 in order:" << endl;
printTree(skewed);
cout << "Height = " << height(skewed) << " (worst case: N-1 = 4)" << endl;
cout << "IsBalanced = " << (isBalanced(skewed) ? "true" : "false") << endl;
cout << endl;
deleteTree(skewed);
// ── 由 Preorder + Inorder 重建 ──
cout << "--- Rebuild from Preorder + Inorder ---\n" << endl;
vector<int> pre = {1, 2, 4, 5, 3, 6};
vector<int> ino = {4, 2, 5, 1, 3, 6};
cout << "Preorder: ";
for (int x : pre) cout << x << " ";
cout << endl;
cout << "Inorder: ";
for (int x : ino) cout << x << " ";
cout << endl;
BSTNode* rebuilt = buildTree(pre, 0, (int)pre.size() - 1,
ino, 0, (int)ino.size() - 1);
cout << "\nRebuilt tree:" << endl;
printTree(rebuilt);
cout << "Verify inorder: ";
inorder(rebuilt);
cout << endl;
// 清理
deleteTree(root);
deleteTree(rebuilt);
return 0;
}
관련 글
Algorithms
java
업데이트 2026-03-02
#include <iostream>.java
#include <iostream>.java — java source code from the Algorithms learning materials (Algorithms/#include <iostream>.java).
글 읽기 →
Algorithms
cpp
업데이트 2026-04-07
748.cpp
748.cpp — cpp source code from the Algorithms learning materials (Algorithms/748.cpp).
글 읽기 →
Algorithms
cpp
업데이트 2026-04-07
827.cpp
827.cpp — cpp source code from the Algorithms learning materials (Algorithms/827.cpp).
글 읽기 →
Algorithms
cpp
업데이트 2026-04-07
827_best_greedy.cpp
827_best_greedy.cpp — cpp source code from the Algorithms learning materials (Algorithms/827_best_greedy.cpp).
글 읽기 →
Algorithms
cpp
업데이트 2026-04-07
8402.cpp
8402.cpp — cpp source code from the Algorithms learning materials (Algorithms/8402.cpp).
글 읽기 →
Algorithms
cpp
업데이트 2026-04-07
860.cpp
860.cpp — cpp source code from the Algorithms learning materials (Algorithms/860.cpp).
글 읽기 →