二进制搜索Tree Seg在删除其根后执行树步行时出错

时间:2013-11-28 06:53:41

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

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

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

然后我调用我的删除函数来删除树的根(Jen),一切似乎都没问题。这就是打印功能应该输出的内容:

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)。一旦找到包含正确数据和密钥的Node,我将调用TREE_DELETE(tmp),其作用是使树中其他节点中的所有指针指向正确的方向。为此,我们将调用TRANSPLANT(传入2个节点指针)来帮助设置节点。我已经多次逐步完成这些算法,当我尝试删除一些元素时,我仍然无法找到程序终止或者出错的原因。最后的注释(我从我的教科书中得到了所有这些算法,所以他们(理论上)应该完美地工作。)

1 个答案:

答案 0 :(得分:0)

打印功能会出错的原因是因为当我在某个指针上调用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;
        }
    }
}