【问题标题】:Seg fault in my delete operation in c++我在 C++ 中的删除操作中出现 Seg 错误
【发布时间】:2014-09-12 21:36:34
【问题描述】:

我正在为 C++ 赋值编写代码,它是使用二叉搜索树的字典实现。我的代码可以编译,但是当我尝试“删除”时,我得到了一个段错误。任何想法为什么会发生。谢谢

这是我的代码

// this function calls the deleteNode function where the deletion is done
void BST::deleteContent(string *word)
{
    deleteNode(word, root);
}
// a helper fuuntion for the deletecontent function
//uses recursion to find the node to be deleted
void BST::deleteNode(const string *word, Node *&nodePtr)
{
    if(word < nodePtr->word)
        deleteNode(word, nodePtr->left);
    else if(word > nodePtr->word)
        deleteNode(word, nodePtr->right);
    else
        makeDeletion(nodePtr);
}
// a helper function for the deleteNode function
void BST::makeDeletion(Node *&nodePtr)
{
    Node *tempNodePtr;

    if(nodePtr == NULL)
        cout<< "cannot delete empty node. \n";
    // if node has no right child
    else if (nodePtr->right == NULL)
        {
            tempNodePtr = nodePtr;
            nodePtr = nodePtr->left; // reattach child
            delete tempNodePtr;
        }
    else if(nodePtr-> left == NULL)
        {
            tempNodePtr = nodePtr;
            nodePtr = nodePtr->right; // reattach child
            delete tempNodePtr;
        }
    // if node has 2 children
    else
        {
            tempNodePtr = nodePtr->right;
            while (tempNodePtr->left)
                tempNodePtr = tempNodePtr->left;
            tempNodePtr->left = nodePtr->left;
            tempNodePtr = nodePtr;
            nodePtr = nodePtr->right;
            delete tempNodePtr;
        }
}

编辑

谢谢大家!!从您的帖子中,我意识到检查节点是否是最后一个并且没有子节点是个好主意。我在 deleteNode 中添加了这个检查

    if((nodePtr->left) && word < nodePtr->word)
    {
        do something
    }

我对右边做了同样的事情 它工作并且没有抛出任何错误或段错误。非常感谢!!!!

【问题讨论】:

  • 如果被删除的单词不在树中,你将递归到一个空节点。然后,当您尝试执行 nodePtr-&gt;word 时,您将取消对空指针的引用。
  • 启用 coredump 并查看回溯。在删除检查 null 和打印输出之前
  • makeDeletion 中,您不处理左右孩子都为空的情况。
  • 几乎需要重写整个makeDeletion 方法。并首先说明您希望它做什么,这样我们就清楚了。
  • 最重要的编程技能之一是调试艺术。这是学习如何做到这一点的主要候选者——尝试单步执行代码,确保每一步都按照您期望的方式执行(并且变量的值是您认为它们应该是的值)。当您发现您的心智模型与实际发生的情况不匹配时,很可能就是代码中的错误所在(或者至少,比最终导致的分段错误更接近该点)。

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


【解决方案1】:

案例1:空树:

假设您的树是空的:root 将是 nullptr。所以deleteContent() 将调用deleteNode() 参数nullptrnodePtr

您要做的第一件事是将wordnodePtr-&gt;word 进行比较,而无需先检查nodePtr 是否不是nullptr。你有第一个分段错误的案例!

案例2:删除一个不在树中的单词:

在这种情况下,deleteNode() 将被递归调用,直到到达没有后代的叶节点。由于搜索到的单词在树中不存在,它要么大于 nodePtr->word,要么小于 nodePtr->word,但从不相等。 deleteNode() 然后会调用自己,再次通过 nodePtr 的参数 nullptr,如案例 1。再次出现分段错误!

案例1和2的解决方案:在deleteNode()中控制nullptr:

void BST::deleteNode(const string *word, Node *&nodePtr)
{
    if (nodePtr==nullptr) 
        cout << word << " not found in the tree\n";
    else if (word < nodePtr->word)
        ...   // the rest as in your original function 
}

makeDeletion() 现在应该由deleteNode() 调用,当且仅当nodePtr 不为空且word==nodePtr-&gt;word。摆脱第一个 if() 在任何情况下都不应该是真的。可以用断言替换它来验证不变量。

案例3:删除树中的一个词:

所有这三种情况似乎都有效(即使是带有两个空指针的叶节点),至少如果我看一下我绘制的数据结构图的话。

但是我建议验证Node::~Node():在所有情况下,您都需要重新附加子节点,然后删除旧节点 (temNodePtr),而无需将其子节点设置为 nullptr .所以我想知道~Node() 是否只是破坏节点而不照顾其子节点(然后makeDeletion() 应该工作)或者如果它是递归析构函数,删除节点及其子节点(然后makeDeletion() 将不起作用,因为你会删除您刚刚重新附加的节点,而不会注意到它,从而在第一次创建 seg.fault)。

顺便说一句,对于指针来说,nullptr 可能比 NULL 更合适,即使 NULL 也能正常工作。

【讨论】:

    猜你喜欢
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 2014-02-27
    • 2014-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多