【问题标题】:c++ bst deleting a node breaks the ordering algorithmsc ++ bst删除节点会破坏排序算法
【发布时间】:2018-09-05 17:23:53
【问题描述】:

我正在尝试为二叉搜索树实现递归删除算法,并已成功完成,但它破坏了排序算法(中序、前序和后序)。这是我的删除功能代码

void remove_rec(string word, Node* ptr) {

        if (word < ptr->data && ptr->left != nullptr) {
            remove_rec(word, ptr->left);
        }
        else if (word > ptr->data && ptr->right != nullptr) {
            remove_rec(word, ptr->right);
        }
        else {
            //if the node has no children
            if (ptr->left == nullptr && ptr->right == nullptr) {
                delete(ptr);
                ptr = nullptr;
            }
            //if there is a right child
            else if (ptr->left == nullptr && ptr->right != nullptr) {
                Node* temp = ptr;
                ptr = ptr->right;
                delete temp;
            }
            //if there is a left child
            else if (ptr->left != nullptr && ptr->right == nullptr) {
                Node* temp = ptr;
                ptr = ptr->left;
                delete temp;
            }
        }
    }

当递归调用中序(或任何其他排序方法)并且左右节点为空时,程序似乎崩溃了。程序没有跳过该 if 语句,而是继续尝试访问左节点,直到它因错误“读取访问冲突”而崩溃。如果我不调用 remove_rec 函数,排序函数将按预期工作。对我来说,似乎在删除节点后我没有正确构建树。任何帮助深表感谢!如果没有调用该函数,我只包含了我认为导致问题的代码,一切都按预期工作。

【问题讨论】:

  • 恢复到刚刚删除的节点上方的树的链接所需的父链接在哪里?如果您只是删除左右为 nullptr 的叶节点,该代码“可能”会正常工作
  • 如果两个孩子都不为 null 并且 word 等于数据怎么办?我认为这是破坏你的算法的原因

标签: c++ recursion binary-search-tree


【解决方案1】:

您并没有修改您认为的指针。线条

ptr = nullptr;

ptr = ptr->right;

ptr = ptr->left;

修改本地参数ptr,它是您Node 的一个子项的独特副本。您需要通过引用传递ptr 才能使修改生效。

您收到“读取访问冲突”的原因是因为节点中指针的 仍然与您删除之前相同,但它现在无效,因为您 @987654325 @d 对象。

你也在复制你正在搜索的数据,这是相当低效的。

void remove_rec(const std::string & word, Node *& ptr) {
    if (word < ptr->data && ptr->left != nullptr) {
        remove_rec(word, ptr->left);
    }
    else if (word > ptr->data && ptr->right != nullptr) {
        remove_rec(word, ptr->right);
    }
    else {
        //if the node has no children
        if (ptr->left == nullptr && ptr->right == nullptr) {
            delete(ptr);
            ptr = nullptr;
        }
        //if there is a right child
        else if (ptr->left == nullptr && ptr->right != nullptr) {
            Node* temp = ptr;
            ptr = ptr->right;
            delete temp;
        }
        //if there is a left child
        else if (ptr->left != nullptr && ptr->right == nullptr) {
            Node* temp = ptr;
            ptr = ptr->left;
            delete temp;
        }
        // TODO: handle case when node has both left and right child
    }
}

另外,我会将Node 更改为使用std::unique_ptr&lt;Node&gt;,因为它是leftright。如果您以后犯类似的错误,您将看到编译时错误。

【讨论】:

  • 即使引用传递,删除中间元素的逻辑仍然不正确。
  • 我知道,但这是一个单独的问题
  • 我不同意在这种情况下使用智能指针的建议。在几乎任何其他情况下,这是正确的建议,但是像二叉搜索树这样的基本数据结构应该是快速且尽可能节省空间的。
  • @MikeBorkland std::unique_ptr&lt;Node&gt; 是对Node * 正确使用的零开销抽象。
猜你喜欢
  • 1970-01-01
  • 2021-04-06
  • 1970-01-01
  • 1970-01-01
  • 2022-08-19
  • 2018-10-11
  • 2014-05-26
  • 2016-11-11
相关资源
最近更新 更多