【问题标题】:Binary search Tree Seg faults when doing a tree walk after removing its root在移除其根后进行树行走时,二叉搜索 Tree Seg 错误
【发布时间】:2013-12-14 02:27:52
【问题描述】:

我一直在使用纸片逐步完成我的功能,看看当我尝试删除第一个节点然后打印它时会发生什么。让我们假设这些是树中已经存在的元素(深度、键、数据)。警告/// 前面的文字墙!

1, 09/17, Paul
0, 10/24, Jen

然后我调用我的删除函数来删除树的根 (Jen),一切似乎都很好。这是 print 函数应该输出的内容:

print
0 9/17 Paul

但是它会出现段错误和输出:

print
0 p▒ p▒ ▒ ▒ ▒#a▒#a$▒#a$▒#ah▒ ... (goes on for a while)
      0 [main] BST 6176 exception::handle: Exception: STATUS_ACCESS_VIOLATION
354 [main] BST 6176 open_stackdumpfile: Dumping stack trace to BST.exe.stackdump

使用 GDB,我输入“where”,希望在我的代码中找到问题所在的哪一行,然后我得到了超乎寻常的响应:

    Program received signal SIGSEGV, Segmentation fault.
0x611298c5 in memchr () from /usr/bin/cygwin1.dll
(gdb) where
#0  0x611298c5 in memchr () from /usr/bin/cygwin1.dll
#1  0x779d34e3 in OutputDebugStringA ()
   from /cygdrive/c/Windows/syswow64/KERNELBASE.dll
#2  0x40010006 in ?? ()
#3  0x00000000 in ?? ()
(gdb)

我希望它会告诉我为什么会出现段错误,但我不知道它可能在哪里。我会在下面放一些源代码(注意:除了某些情况下的删除部分之外,整个程序都可以工作。)我的程序有时会突然结束或以 Aborted(核心转储)终止。树走总是有效的,我已经插入了数千个元素,它总是会完美地输出它们。以下是以下类:Node.h

#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED

#include <iostream>
#include <string>

using namespace std;

//class BST;
class Node
{
public:
    Node(string key, string data)
    {m_key = key; m_data = data;}
    ~Node(){
       delete m_left;
       delete m_right;
    }
    friend class BST;
private:
    string m_key;
    string m_data;
    Node *m_left;
    Node *m_right;
    Node *m_parent;
};


#endif // NODE_H_INCLUDED

BST.h

#ifndef BST_H_INCLUDED
#define BST_H_INCLUDED

#include <iostream>
#include <string>

using namespace std;
class Node;
class BST
{
public:
    BST()
    {m_root = NULL;}
    ~BST();
    void insert(string key, string data);

    void find(string key);
    Node* TREE_SEARCH(Node* ptr, string key);

    void remove(string key, string data);
    void TREE_DELETE(Node* ptr);
    void TRANSPLANT(Node* ptr, Node* ptr);
    Node* TREE_MINIMUM(Node* ptr);

    void print();
    void IN_ORDER_TREE_WALK(Node* ptr, int depth);
    //friend class Node;
private:
    Node* m_root;

};

#endif // BST_H_INCLUDED

这是 BST.cpp(请注意,在我正在制作的帖子中,我没有包含任何已经在我的程序中工作的函数。另外,为了更容易阅读,我将只显示析构函数和所有需要的函数删除一个节点。):BST.cpp

#include "BST.h"
#include "Node.h"
BST::~BST()
{
    delete m_root;
    m_root = NULL;
}
Node* BST::TREE_SEARCH(Node* ptr, string key)
{
    //if(ptr != NULL)
        //cout << "SEARCHING: " <<ptr->m_key<<", " << ptr->m_data << endl;
    if(ptr == NULL || ptr->m_key == key)
        return ptr;
    if(key < ptr->m_key)
        return TREE_SEARCH(ptr->m_left, key);
    else return TREE_SEARCH(ptr->m_right, key);
}
void BST::remove(string key, string data)
{
    //cout << "preparing to remove..." << endl;
    Node* ptr = m_root;
    //if(m_root)
    Node* tmp = TREE_SEARCH(ptr, key);
    while(tmp != NULL)
    {
        if(tmp->m_data == data)
        {
            cout << "DELETE: " << tmp->m_key << ", " << tmp->m_data << endl << endl;
            TREE_DELETE(tmp);
            //Node* del = tmp;
            //delete del;
            delete tmp;
            return;
            //tmp = NULL;
        }
        else
        {
            cout << "Iterating" << endl;
            tmp = tmp->m_right; //this is the issue
        }
    }
}
void BST::TREE_DELETE(Node* z)
{
    //cout << "Changing pointers" << endl;
    if(z->m_left == NULL)
        TRANSPLANT(z, z->m_right);
    else if(z->m_right == NULL)
        TRANSPLANT(z, z->m_left);
    else
    {
        Node* y = TREE_MINIMUM(z->m_right);
        if(y->m_parent != z)
        {
            TRANSPLANT(y, y->m_right);
            y->m_right = z->m_right;
            y->m_right->m_parent = y;
        }
        TRANSPLANT(z, y);
        y->m_left = z->m_left;
        if(y->m_left != NULL)// I added this
            y->m_left->m_parent = y;
    }


}
void BST::TRANSPLANT(Node* u, Node* v)
{
    //cout << "TRANSPLANT" << endl;
    if(u->m_parent == NULL)
    {
        m_root = v;
    }
    else if(u == u->m_parent->m_left)
    {
        u->m_parent->m_left = v;
    }
    else
    {
        u->m_parent->m_right = v;
    }
    if(v != NULL)
    {
        v->m_parent = u->m_parent;
    }
}

Node* BST::TREE_MINIMUM(Node* x)
{
    //cout << "GET MIN" << endl;
    //x = m_root;
    while(x->m_left != NULL)
        x = x->m_left;
    return x;
}

我将尽我所能解释所有这些功能的工作原理。我们从int main() 开始,我们将调用remove(key, data) [我们传入将放入树中节点的键和数据]。删除后,我们将设置一个指向m_root 的指针并调用搜索函数(效果很好,我用一个在树中查找元素但不删除它们的函数对其进行了测试)。该函数将返回一个指向我们要删除的元素的指针。注意:对于这个分配(日历分配),每个日期(10/24)可能有多个事情,所以我必须向右横向,直到找到我正在寻找的数据(Jen)。一旦找到包含正确数据和键的节点,我将调用TREE_DELETE(tmp),其工作是获取树中其他节点中指向正确方向的所有指针。为此,我们将调用TRANSPLANT(传入 2 个节点指针)来帮助设置节点。我已经多次遍历这些算法,但当我尝试删除某些元素时,我仍然无法找出程序终止或段错误的原因。最后说明(我从教科书中得到了所有这些算法,所以它们(理论上)应该可以完美运行。)

【问题讨论】:

  • 如果根节点被移除,那改变m_root的代码在哪里?
  • 你试过调试它吗?尤其要检查Nodes 析构函数调用发生了什么。
  • 在一张纸上单步执行我的代码时,我注意到它可以正确处理 m_root(不过我可能错了)。
  • 加上ALL_CAPS_WITH_UNDERSCORES中的所有代码均来自教科书
  • 您说TREE_DELETE 正确设置了other 节点中的所有指针,但它是否也将tmp 中的指针设置为NULL?如果没有,那么delete tmp; 也会从你的树中删除其他几个节点。

标签: c++ algorithm binary-search-tree destructor delete-operator


【解决方案1】:

打印函数会出现段错误的原因是因为当我在那个特定的指针上调用 delete 时,它​​会删除它下面的所有内容。我的解决方案是:[再次感谢约翰]

void BST::remove(string key, string data)
{
    Node* ptr = m_root;
    Node* tmp = TREE_SEARCH(ptr, key);
    while(tmp != NULL)
    {
        if(tmp->m_data == data)
        {
            TREE_DELETE(tmp);
            tmp->m_parent = NULL;
            tmp->m_right = NULL;
            tmp->m_left = NULL;
            delete tmp;
            return;
        }
        else
        {
            tmp = tmp->m_right;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-16
    • 1970-01-01
    • 2021-08-22
    • 2016-09-18
    • 1970-01-01
    • 1970-01-01
    • 2017-06-12
    • 1970-01-01
    相关资源
    最近更新 更多