【发布时间】: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