二叉排序树
一、二叉排序树的定义
- 性质:
- 对于每个节点 N,满足:
- 若左子树不为空,则左子树中所有节点的值均小于 N 的值。
- 若右子树不为空,则右子树中所有节点的值均大于 N 的值。
- 左右子树本身也必须是二叉排序树。
- 特点:
- 中序遍历的结果是一个升序排列的序列。
- 数据存储动态且可扩展,适合频繁的插入、删除和查找操作。
二、二叉排序树的基本操作
1. 定义节点结构
二叉排序树的节点通常包括数据值和左右子树指针:
1 2 3 4 5 6 7
| struct TreeNode { int value; TreeNode* left; TreeNode* right;
TreeNode(int val) : value(val), left(nullptr), right(nullptr) {} };
|
2. 插入节点
插入节点时递归定位插入位置,保持二叉排序树的性质:
1 2 3 4 5 6 7 8
| TreeNode* insert(TreeNode* root, int value) { if (!root) return new TreeNode(value); if (value < root->value) root->left = insert(root->left, value); else if (value > root->value) root->right = insert(root->right, value); return root; }
|
3. 查找节点
从根节点开始,递归或迭代查找目标值:
1 2 3 4 5 6
| TreeNode* search(TreeNode* root, int value) { if (!root || root->value == value) return root; if (value < root->value) return search(root->left, value); return search(root->right, value); }
|
4. 删除节点
删除节点需分三种情况处理:
节点为叶子节点:直接删除。
节点有一个子节点:用子节点替代。
节点有两个子节点:用右子树的最小节点[待删除结点的 中序直接后](或左子树的最大节点[待删除结点的 中序直接前驱])替代,然后删除该节点。
待删除结点左右子树都存在,有两种处理方式:
(1) 用其右子树中序遍历第一个结点(关键码最小)填补其位置,再来处理这个结点的删除 问题
(2) 用其左子树中序遍历最后一个结点(关键码最大)填补其位置,再来处理这个结点的删 除问题 这两种方式中用来填补的结点要么是叶子结点,要么只有左子树或右子树,即是前三种情形
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| TreeNode* findMin(TreeNode* root) { while (root && root->left) root = root->left; return root; }
TreeNode* deleteNode(TreeNode* root, int value) { if (!root) return nullptr; if (value < root->value) root->left = deleteNode(root->left, value); else if (value > root->value) root->right = deleteNode(root->right, value); else { if (root->left && root->right) { TreeNode* temp = findMin(root->right); root->value = temp->value; root->right = deleteNode(root->right, temp->value); } else { TreeNode* temp = root->left ? root->left : root->right; delete root; return temp; } } return root; }
|
5. 遍历
1 2 3 4 5 6
| void inorderTraversal(TreeNode* root) { if (!root) return; inorderTraversal(root->left); cout << root->value << " "; inorderTraversal(root->right); }
|
1 2 3 4 5 6
| void preorderTraversal(TreeNode* root) { if (!root) return; cout << root->value << " "; preorderTraversal(root->left); preorderTraversal(root->right); }
|
1 2 3 4 5 6
| void postorderTraversal(TreeNode* root) { if (!root) return; postorderTraversal(root->left); postorderTraversal(root->right); cout << root->value << " "; }
|
三、二叉排序树的完整实现
以下是一个完整的 C++ 示例代码,包含插入、查找、删除和遍历功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| #include <iostream> using namespace std;
struct TreeNode { int value; TreeNode* left; TreeNode* right;
TreeNode(int val) : value(val), left(nullptr), right(nullptr) {} };
TreeNode* insert(TreeNode* root, int value) { if (!root) return new TreeNode(value); if (value < root->value) root->left = insert(root->left, value); else if (value > root->value) root->right = insert(root->right, value); return root; }
TreeNode* search(TreeNode* root, int value) { if (!root || root->value == value) return root; if (value < root->value) return search(root->left, value); return search(root->right, value); }
TreeNode* findMin(TreeNode* root) { while (root && root->left) root = root->left; return root; }
TreeNode* deleteNode(TreeNode* root, int value) { if (!root) return nullptr; if (value < root->value) root->left = deleteNode(root->left, value); else if (value > root->value) root->right = deleteNode(root->right, value); else { if (!root->left) { TreeNode* temp = root->right; delete root; return temp; } if (!root->right) { TreeNode* temp = root->left; delete root; return temp; } TreeNode* temp = findMin(root->right); root->value = temp->value; root->right = deleteNode(root->right, temp->value); } return root; }
void inorderTraversal(TreeNode* root) { if (!root) return; inorderTraversal(root->left); cout << root->value << " "; inorderTraversal(root->right); }
int main() { TreeNode* root = nullptr; root = insert(root, 50); root = insert(root, 30); root = insert(root, 70); root = insert(root, 20); root = insert(root, 40); root = insert(root, 60); root = insert(root, 80);
cout << "Inorder Traversal: "; inorderTraversal(root); cout << endl;
cout << "Searching for 40: " << (search(root, 40) ? "Found" : "Not Found") << endl;
root = deleteNode(root, 50); cout << "After deleting 50, Inorder Traversal: "; inorderTraversal(root); cout << endl;
return 0; }
|
四、复杂度分析
- 查找、插入、删除:
- 平均时间复杂度:O(logn)O(\log n)O(logn)。
- 最坏时间复杂度:O(n)O(n)O(n)(退化为链表时)。
- 空间复杂度:O(h)O(h)O(h)(递归调用栈深度,hhh 为树的高度)。
五、改进方向
- 平衡性:
- 普通 BST 在最坏情况下会退化为链表,导致效率降低。
- 可用 AVL 树 或 红黑树 进行平衡优化。
- 扩展数据结构:
- B 树、B+ 树:适合磁盘存储和大规模数据管理。
- Trie 树:适合字符串存储和快速匹配。