You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中二叉搜索树(BST)删除节点引发其他方法报错求助

Fixing Dangling Pointer Issue When Deleting Leaf Nodes in C++ BST

嘿,我帮你找出问题所在了!你遇到的0xDDDD...错误是典型的悬空指针访问问题,根源出在你删除叶子节点的逻辑上,还有查找逻辑里藏了个小bug,咱们一步步拆解修复:

1. 核心问题:未更新父节点的指针

你的deleteNodeByValue方法里,找到叶子节点后直接执行delete tmp; tmp = NULL;——但tmp只是个临时指针,父节点的left_child或right_child仍然指向已经被释放的内存地址。比如如果要删的节点是父节点的左孩子,父节点的left_child还是原来的地址,而那块内存已经被标记为释放(就是你看到的0xDDDD...,这是VS用来标记已释放内存的特殊值),后续遍历、打印时访问这个悬空指针就会触发错误。

所以我们必须追踪父节点,明确当前节点是父节点的左孩子还是右孩子,这样删除后才能把父节点对应的指针置空,彻底从树结构中移除这个节点。

2. 查找逻辑的小bug

你最后一个分支的条件写错了:else if (val < root->data)应该是else if (val < tmp->data),不然永远只会和根节点比较,左子树的查找完全失效,根本找不到正确的节点。

3. 修复后的完整代码示例

修复的deleteNodeByValue方法

void deleteNodeByValue(T val) {
    cout << "\nElement to delete: " << val << " \n";
    Node<T>* current = root;
    Node<T>* parent = nullptr;
    bool isLeftChild = false;

    // 查找目标节点及其父节点
    while (current != nullptr) {
        if (val == current->data) {
            cout << "Element found: " << current->data << " \n";
            // 处理叶子节点场景
            if (current->right_child == nullptr && current->left_child == nullptr) {
                // 特殊情况:要删除的是根节点(没有父节点)
                if (parent == nullptr) {
                    root = nullptr;
                } 
                // 更新父节点的左指针
                else if (isLeftChild) {
                    parent->left_child = nullptr;
                } 
                // 更新父节点的右指针
                else {
                    parent->right_child = nullptr;
                }
                delete current;
                size--;
            }
            break;
        } 
        // 去右子树查找
        else if (val > current->data) {
            parent = current;
            current = current->right_child;
            isLeftChild = false;
        } 
        // 去左子树查找
        else {
            parent = current;
            current = current->left_child;
            isLeftChild = true;
        }
    }
}

优化后的树打印方法(避免命名冲突+逻辑更清晰)

你的打印方法还有个小问题:和标准库的std::to_string重名了,容易引发编译问题,这里改成toString(),同时优化了空树的处理:

string toString() {
    stringstream ss;
    // 处理空树的情况
    if (root == nullptr) {
        ss << "Tree is empty\n";
        return ss.str();
    }

    queue<Node<T>*> q;
    q.push(root);

    while (!q.empty()) {
        Node<T>* current = q.front();
        q.pop();

        ss << "Data: " << current->data;
        // 左孩子处理
        if (current->left_child != nullptr) {
            ss << " Left child: " << current->left_child->data;
            q.push(current->left_child);
        } else {
            ss << " Left child: null";
        }
        // 右孩子处理
        if (current->right_child != nullptr) {
            ss << " Right child: " << current->right_child->data;
            q.push(current->right_child);
        } else {
            ss << " Right child: null";
        }
        ss << "\n";
    }
    return ss.str();
}

为什么之前会出现0xDDDD...错误?

在Visual Studio环境中,内存被delete后会被填充为0xDDDDDDDD,用来标记这块内存已经被释放。你的旧代码删除叶子节点后,父节点的指针仍然指向这块已释放的内存,当打印方法遍历到这个指针并尝试访问tmp->left_child时,就会触发非法内存访问错误。

额外建议

  • 后续实现非叶子节点的删除(单孩子、双孩子场景)时,同样要注意更新父节点的指针,以及根节点的特殊处理。
  • 可以在删除操作后立刻调用打印方法,验证树结构是否正确,提前发现悬空指针问题。

内容的提问来源于stack exchange,提问作者GSaple

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 20:03:11