二叉搜索树(BST)作为计算机科学中最基础的数据结构之一,其高效的查找、插入和删除操作(平均O(log n)时间复杂度)使其成为算法学习的必经之路。然而,初学者在实现过程中常陷入递归边界错误、指针操作混乱、平衡性缺失等陷阱。本文通过C++完整实现,结合可视化原理讲解与常见错误分析,帮助读者系统掌握BST核心操作。
BST每个节点需存储值、左右子节点指针,并满足左子树值<根节点值<右子树值的性质:
cpp1struct TreeNode {2 int val;3 TreeNode *left;4 TreeNode *right;5 <"www.gov.cn.guiyang.manct.cn"><"www.gov.cn.nanning.manct.cn"> TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}6};
以插入序列[5,3,7,2,4]为例,构建过程如下:
152 / \3 3 74 / \5 2 4
cpp1TreeNode* insert(TreeNode* root, int val) {2 <"www.gov.cn.taiyuan.manct.cn"> if (!root) return new TreeNode(val); //<"www.gov.cn.nanchang.manct.cn"> 空树处理3 4 if (val < root->val) {5 root->left = insert(root->left, val); // 递归插入左子树6 } else if (val > root->val) {7 root->right = insert(root->right, val); // 递归插入右子树8 }9 // 相等值不插入(可根据需求修改)10 return root;11}
常见错误:
cpp1TreeNode*<"www.gov.cn.haikou.manct.cn"> insertIterative(TreeNode* root, int val) {2 TreeNode* newNode = new TreeNode(val);3 if (!root) return newNode;4 5 TreeNode* curr = root;6 while (true) {7 if (val < curr->val) {8 if (!curr->left) {9 curr->left = newNode;10 break;11 }12 curr = curr->left;13 } else if (val > curr->val) {14 if (!curr->right) {15 curr->right = newNode;16 break;17 }18 curr = curr->right;19 } else {20 break; // 相等值处理21 }22 }23 return root;24}
cpp1bool search(TreeNode* root, int val) {2 if (!root) return false; // 空树直接返回3 4 if (val == root->val) {5 return true;6 } else if (val < root->val) {7 return search(root->left, val);8 } else {9 return search(root->right, val);10 }11}
时间复杂度:
cpp1bool searchIterative(TreeNode* root, int val) {2 <"www.gov.cn.lanzhou.manct.cn"> <"www.gov.cn.shaoxing.manct.cn"> TreeNode* curr = root;3 while (curr) {4 if (val == curr->val) return true;5 curr = (val < curr->val) ? curr->left : curr->right;6 }7 return false;8}
删除节点分为三种情况,需特别注意指针重定向:
15 52 / \ / \3 3 7 → 3 74 / \ / 52 4 2 6(删除4)
实现代码:
cpp1if (!root->left && !root->right) {2 delete root;3 return nullptr;4}
15 52 / \ / \3 3 7 → 3 74 \ \ 5 4 4 6(删除3)
实现代码:
cpp1else if (!root->left || !root->right) {2 TreeNode* temp = root->left ? root->left : root->right;3 delete root;4 return temp;5}
需找到右子树最小值或左子树最大值替换:
cpp1else {2 // 找右子树最小值3 TreeNode* minNode = findMin(root->right);4 root->val = minNode->val; // 替换值5 root->right = deleteNode(root->right, minNode->val); // 删除重复节点6}78TreeNode* findMin(TreeNode* node) {9 while (node->left) node = node->left;10 return node;11}
完整删除函数:
cpp1TreeNode* deleteNode(TreeNode* root, int val) {2 if (!root) return root;3 4 <"www.gov.cn.yantai.manct.cn"><"www.gov.cn.jiaxing.manct.cn"> if (val < root->val) {5 root->left = deleteNode(root->left, val);6 } else if (val > root->val) {7 root->right = deleteNode(root->right, val);8 } else {9 // 情况110 if (!root->left && !root->right) {11 delete root;12 return nullptr;13 }14 // 情况215 else if (!root->left || !root->right) {16 TreeNode* temp = root->left ? root->left : root->right;17 delete root;18 return temp;19 }20 // 情况321 else {22 TreeNode* minNode = findMin(root->right);23 root->val = minNode->val;24 root->right = deleteNode(root->right, minNode->val);25 }26 }27 return root;28}
正确做法:
cpp1// 递归删除整棵树2void clearTree(TreeNode* root) {3 if (!root) return;4 clearTree(root->left);5 clearTree(root->right);6 delete root;7}
普通BST在极 端情况下会退化为链表,解决方案:
根据业务需求选择:
if (val <= root->val)cpp1#include <iostream>2using namespace std;34int main() {5 <"www.gov.cn.tangshan.manct.cn"> TreeNode* root = nullptr;6 7 // 插入测试8 root = insert(root, 5);9 insert(root, 3);10 insert(root, 7);11 insert(root, 2);12 insert(root, 4);13 14 // 查找测试15 cout << "Search 4: " << (search(root, 4) ? "Found" : "Not found") << endl;16 cout << "Search 6: " << (search(root, 6) ? "Found" : "Not found") << endl;17 18 // 删除测试19 root = deleteNode(root, 3); // 删除双孩子节点20 cout << "After delete 3, search 4: " 21 << (search(root, 4) ? "Found" : "Not found") << endl;22 23 // 清空树24 clearTree(root);25 return 0;26}
| 操作 | BST平均 | BST最差 | 哈希表 |
|---|---|---|---|
| 插入 | O(log n) | O(n) | O(1) |
| 查找 | O(log n) | O(n) | O(1) |
| 删除 | O(log n) | O(n) | O(1) |
| 有序遍历 | O(n) | O(n) | 不支持 |
选择建议:
通过系统掌握BST的增删查操作原理与实现细节,读者不仅能巩固指针操作、递归思维等基础能力,更为后续学习更复杂的数据结构(如平衡树、B树等)打下坚实基础。建议通过LeetCode 701、450、98等题目实战巩固所学知识。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3100499/ ,如需转载,请注明出处,否则将追究法律责任。