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

二叉搜索树(BST)删除函数实现正确性咨询

二叉搜索树(BST)删除函数实现疑问

我正在实现一个基础的二叉搜索树(BST),希望获得删除函数的相关帮助。以下是我对节点删除逻辑的理解:

  • 删除叶子节点:直接移除该节点(修改其父节点的指针)并返回其数据
  • 删除仅含左子节点的节点:移除该节点,将其父节点的对应子节点设为该节点的左子节点
  • 删除内部节点:需用右子树中最小的节点替代当前节点,若替代节点有右子节点,则让其占据替代节点原位置

请问以下代码是否正确实现了上述逻辑?

// main function to remove node with "data"
template <typename T>
T BSTree<T>::delete(T& data){
    // BSTree is empty
    if (root == NULL){
        return root;
    }
    return delete(root, data);
}

// recursive function to locate the node to be removed and alter the respective pointers
template <typename T>
T BSTree<T>::delete(BTNode<T>* node, T& data){
    // "data" is to the left of sub-tree
    if (node->getData() > data){
        return delete(node->getLeft(), data);
    }
    // "data" is to the right of sub-tree
    else if (node->getData() < data){
        return delete(node->getRight(), data);
    }

    // now, node points to the node with "data"

    // if node is leaf; delete the node and any pointers to it
    if (node->getLeft() == NULL and node->getRight() == NULL){
        // if node is the left child; parents left child will be null
        if (node->getParent()->getData() > data){
            node->getParent()->setLeft(NULL);
        }
        // node is the right child; parents right child will be null
        else{
            node->getParent()->setRight(NULL);
        }
    }
    else{
        // node to be deleted has only the left child
        if (node->getRight() == NULL){
            node->getLeft()->setParent(node->getParent);
            // if node is the left child; parents left child will be nodes left child
            if (node->getParent()->getData() > data){
                node->getParent()->setLeft(node->getLeft());
            }
            // node is the right child; parents right child will be nodes left child
            else{
                node->getParent()->setRight(node->getLeft());
            }
        }
        // node to be deleted has both children
        else{
            BTNode<T>* deleteNode = node;
            // iterate to the smallest from the right sub-tree
            node = node->getRight();
            while(node->getLeft()){
                node = node->getLeft();
            }
            // if the substitute has a right child; put it in the substitutes place
            if (node->getRight()){
                node->getParent()->setLeft(node->getRight());
                node->getLeft()->setParent(node->getParent());
            }
            // replace deleteNode and node (ie substitute node)
            node->setParent(deleteNode->getParent());
            // if deleteNode is the left child; parents left child will be node
            if (deleteNode->getParent()->getData() > data){
                deleteNode->getParent()->setLeft(node);
            }
            // deleteNOde is the right child; parents right child will be node
            else{
                deleteNode->getParent()->setRight(node);    
            }
            node = deleteNode;
        }
    }
    delete node;
    return data;
}

代码问题分析

你的思路方向符合BST删除的基本逻辑,但代码存在多个编译错误和逻辑漏洞,无法正确运行:

  1. 关键字冲突:delete是C++的关键字,不能用作函数名,编译会直接报错,建议改为remove或deleteNode。

  2. 返回值类型不匹配:

    • 主函数返回类型是T,但树为空时返回root(指针类型),类型完全不兼容;
    • 递归函数同样返回T,但递归调用逻辑需要返回修改后的子树根节点指针,而非被删除的数据,否则无法更新父节点的指针,树结构不会变化。
  3. 根节点处理缺失:当待删除节点是根节点时,node->getParent()为空指针,访问其成员会触发空指针异常,代码完全未覆盖这种场景。

  4. 递归逻辑错误:递归查找待删除节点时,直接返回子函数结果但未更新当前节点的左/右指针,导致父节点的指针永远不会被修改,删除操作无法生效。

  5. 语法错误:仅左子节点分支中,node->getLeft()->setParent(node->getParent);少了函数调用括号,应为node->getParent(),否则会传递函数地址而非父节点指针,编译失败。

  6. 内部节点替换逻辑漏洞:

    • 替代节点(右子树最小节点)的左子节点必然为空,代码中node->getLeft()->setParent(...)会触发空指针访问,正确操作应为给替代节点的右子节点设置父节点;
    • 未将被删除节点的左子树挂载到替代节点上,会丢失左子树数据;
    • 当替代节点是被删除节点的直接右子节点时,node->getParent()指向被删除节点本身,此时设置父节点指针会出现逻辑错误。

修正后的核心逻辑参考

递归删除函数应设计为返回BTNode<T>*类型,通过返回修改后的子节点自动更新父节点指针,同时简化根节点和内部节点的处理:

template <typename T>
BTNode<T>* BSTree<T>::remove(BTNode<T>* node, T& data) {
    if (node == nullptr) return nullptr;

    if (data < node->getData()) {
        node->setLeft(remove(node->getLeft(), data));
        if (node->getLeft() != nullptr) {
            node->getLeft()->setParent(node);
        }
    } else if (data > node->getData()) {
        node->setRight(remove(node->getRight(), data));
        if (node->getRight() != nullptr) {
            node->getRight()->setParent(node);
        }
    } else {
        // 处理叶子节点/单子节点情况
        if (node->getLeft() == nullptr) {
            BTNode<T>* temp = node->getRight();
            delete node;
            return temp;
        }
        if (node->getRight() == nullptr) {
            BTNode<T>* temp = node->getLeft();
            delete node;
            return temp;
        }
        // 找右子树最小节点
        BTNode<T>* temp = node->getRight();
        while (temp->getLeft() != nullptr) {
            temp = temp->getLeft();
        }
        // 替换数据而非移动节点
        node->setData(temp->getData());
        // 删除替代节点
        node->setRight(remove(node->getRight(), temp->getData()));
        if (node->getRight() != nullptr) {
            node->getRight()->setParent(node);
        }
    }
    return node;
}

这种实现通过数据替换简化了内部节点的删除逻辑,同时自动处理了父节点指针更新和根节点场景,避免了空指针风险。

内容的提问来源于stack exchange,提问作者Avishek Sapkota Sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 22:12:10