bst插入查找核心是递归比较左右子树,空位插入、等值返回;新手易错在指针传参(须用引用或二级指针)、内存泄漏(new/delete不匹配)和边界判空(!root不可省)。

直接说结论:BST 的插入和查找核心就两条——递归走左子树(值小)或右子树(值大),空节点处插入,相等即查到;但新手常卡在指针传参、内存泄漏和边界判空上。
插入操作必须用二级指针或引用传参
如果只传 TreeNode*,函数内对指针的修改(比如 root = new TreeNode(val))不会反映到调用方。C++ 没有“指针的指针”自动解引用,必须显式处理。
推荐写法是传 TreeNode*&(引用):
void insert(TreeNode*& root, int val) {
if (!root) {
root = new TreeNode(val); // ✅ 修改生效
return;
}
if (val < root->val) insert(root->left, val);
else if (val > root->val) insert(root->right, val);
// val == root->val 不插入(去重)
}- 别用
void insert(TreeNode* root, ...)+ 返回新指针,容易漏接返回值 - 如果坚持用一级指针,必须传
TreeNode**,然后写*root = new TreeNode(...) - 每次
new后没配对delete是常见内存泄漏源头
查找函数返回指针而非 bool 更实用
单纯判断“是否存在”用 bool 足够,但实际中往往需要拿到那个节点(比如后续删它、改值、访问父节点)。所以返回 TreeNode* 更通用:
立即学习“C++免费学习笔记(深入)”;
TreeNode* search(TreeNode* root, int val) {
if (!root || root->val == val) return root;
if (val < root->val) return search(root->left, val);
return search(root->right, val);
}- 返回
nullptr表示未找到,比bool多一层安全校验 - 注意不能省略
!root判空,否则root->val会崩溃 - 非递归写法虽省栈空间,但代码变长且易错(尤其 while 循环里忘记更新当前节点)
构造函数和析构要配套管理内存
手撕 BST 时,TreeNode 类通常只是数据载体,但整棵树的生命周期得有人管。不写析构函数,delete root 只删根,子树全 leaked。
简单可靠的递归析构:
void destroy(TreeNode* root) {
if (!root) return;
destroy(root->left);
destroy(root->right);
delete root;
}- 顺序必须是:先递归销毁左右子树,再
delete当前节点 - 如果 BST 封装成类(如
class BST),应在析构函数里调用destroy(root),并把root置为nullptr - 现代 C++ 更推荐用
std::unique_ptr<treenode></treenode>,自动管理,但手撕练习时不建议绕开裸指针直面问题
真正难的不是写对逻辑,而是每次插入后手动画图验证指针连得对不对;一两个节点看不出问题,插十个数后找不着某个节点,八成是某次 root = ... 写成了局部赋值。










