我正在编写代码以递归方式从BST中删除节点,主要是作为一项研究练习来实现重复并验证我对我使用过的某些编码元素的理解。在这种情况下,问题似乎是通过引用将指针传递给我的BST节点。
我的BST代码的psrt如下。 (这不是我要实现或使用的代码。只是一个练习。我选择BST作为一个例子来实现我想用语言尝试的一些东西)
标题 -
//BST.h
class TNode
{
public:
TNode():data(0), left(0), right(0) {}
int data;
TNode* left;
TNode* right;
};
class BST
{
private:
TNode* Head;
public:
BST();
void InsertData(int data);
void InsertNode(TNode* node);
void DeleteData(int data);
private:
void InsertDataPrivate(int data, TNode* &root);
void InsertNodePrivate(TNode* node, TNode* &root);
void DeleteDataPrivate(int data, TNode* &root);
};
CPP -
//BST.cpp
#include "BST.h"
BST::BST(): Head(0)
{
}
void BST::InsertData(int data)
{
InsertDataPrivate(data, Head);
}
void BST::InsertNode(TNode* node)
{
InsertNodePrivate(node, Head);
}
void BST::DeleteData(int data)
{
DeleteDataPrivate(data, Head);
}
void BST::InsertDataPrivate(int data, TNode* &root)
{
if(root == 0)
{
root = new TNode();
root->data = data;
}
else if(data < root->data) InsertDataPrivate(data, root->left);
else if(data > root->data) InsertDataPrivate(data, root->right);
}
void BST::InsertNodePrivate(TNode* node, TNode* &root)
{
if(root == 0) // Deep Copy
{
root = new TNode();
root->data = node->data;
}
else if(node->data < root->data) InsertNodePrivate(node, root->left);
else if(node->data > root->data) InsertNodePrivate(node, root->right);
}
void BST::DeleteDataPrivate(int data, TNode* &root)
{
if( 0 == root ) return;
if( root->data == data )
{
if(0 == root->left && 0 == root->right)
{
delete root;
root = 0;
}
else if(0 == root->left)
{
TNode* current = root;
root = root->right;
delete current;
current = 0;
}
else if(0 == root->right)
{
TNode* current = root;
root = root->left;
delete current;
current = 0;
}
else
{
TNode* biggestOnLeft = root->left;
TNode* smallestOnRight = root->right;
int i = 0;
while (biggestOnLeft->right) // check if left subtree is longer than right subtree
{
biggestOnLeft = biggestOnLeft->right;
--i;
}
while (smallestOnRight->left)
{
smallestOnRight = smallestOnRight->left;
++i;
}
if(i < 0) // left subtree is longer than right subtree
{
root->data = biggestOnLeft->data;
DeleteDataPrivate(biggestOnLeft->data, biggestOnLeft);
}
else // right subtree is longer than or equal in size to left subtree
{
root->data = smallestOnRight->data;
DeleteDataPrivate(smallestOnRight->data, smallestOnRight);
}
}
}
else if(data < root->data && 0 !=root->left)
{
DeleteDataPrivate(data, root->left);
}
else if(data > root->data && 0 !=root->right)
{
DeleteDataPrivate(data, root->right);
}
}
我的测试代码如下 -
//TestMain.cpp
#include "stdafx.h"
#include "BST.h"
int _tmain(int argc, _TCHAR* argv[])
{
BST bst;
bst.InsertData(32);
bst.InsertData(46);
bst.InsertData(3463);
bst.InsertData(32);
bst.InsertData(856);
bst.InsertData(8098);
bst.InsertData(345);
bst.InsertData(234554);
bst.InsertData(77);
bst.InsertData(9);
bst.InsertData(15);
bst.InsertData(390);
bst.InsertData(350);
bst.InsertData(400);
bst.InsertData(76);
bst.InsertData(78);
bst.InsertData(355);
bst.DeleteData(77);
return 0;
}
在我说bst.DeleteData(77);
的最后一步中,我遇到了问题。具有'77'的节点被删除正常并被替换为'78',以便从BST中删除具有两个子节点的节点。但是,在删除具有'78'的节点之后删除具有'77'的父节点仍然指向非空位置。
我正在调用我的私有函数DeleteDataPrivate(int data, TNode* &root);
,它在删除后将TNode指针设置为NULL。此外,我在函数中传递指针引用,以便在递归堆栈展开时将NULL值分配给已删除的节点指针。这不会发生。有人可以解释我在这里做错了吗?
谢谢。
Chinmay
更新
根据Dan在下面的评论,问题在于将值传递给局部变量,这些变量制作了我的指针副本并且没有分配给任何东西。我已经通过使用指向指针来修改我的函数以解决这个问题,以便由展开递归返回的TNode指针的值存储在内存中的正确位置而不是TNode指针的某个副本中。
修改后的功能如下
void BST::DeleteDataPrivate(int data, TNode* &root)
{
if( 0 == root ) return;
if( root->data == data )
{
if(0 == root->left && 0 == root->right)
{
delete root;
root = 0;
}
else if(0 == root->left)
{
TNode* current = root;
root = root->right;
delete current;
current = 0;
}
else if(0 == root->right)
{
TNode* current = root;
root = root->left;
delete current;
current = 0;
}
else
{
TNode* biggestOnLeft = root->left;
TNode* smallestOnRight = root->right;
int i = 0;
while (biggestOnLeft->right) // check if left subtree is longer than right subtree
{
biggestOnLeft = biggestOnLeft->right;
--i;
}
while (smallestOnRight->left)
{
smallestOnRight = smallestOnRight->left;
++i;
}
TNode** locationOfDeletedNode = 0;
if(i < 0) // left subtree is longer than right subtree
{
locationOfDeletedNode = &(root->left);
while(*locationOfDeletedNode != biggestOnLeft) locationOfDeletedNode = &((*locationOfDeletedNode)->right);
}
else // right subtree is longer than or equal in size to left subtree
{
locationOfDeletedNode = &(root->right);
while(*locationOfDeletedNode != smallestOnRight) locationOfDeletedNode = &((*locationOfDeletedNode)->left);
}
root->data = (*locationOfDeletedNode)->data;
DeleteDataPrivate((*locationOfDeletedNode)->data, *locationOfDeletedNode);
}
}
else if(data < root->data && 0 !=root->left)
{
DeleteDataPrivate(data, root->left);
}
else if(data > root->data && 0 !=root->right)
{
DeleteDataPrivate(data, root->right);
}
}
当然,这可以更好地结构化,但我的目标是在这里学习简单而棘手的事情,感谢Dan和其他人在这里做过的。
答案 0 :(得分:5)
致电时
DeleteDataPrivate(biggestOnLeft->data, biggestOnLeft);
它只是分配给局部变量biggestOnLeft
,它不会分配给任何对象的成员。
因为你做的时候
TNode* biggestOnLeft = root->left;
它创建了一个新变量,它是root->left
的副本,而不是同一个东西。
您可以尝试在root用户启动biggestOnLeft
和smallestOnRight
,然后执行
while (biggestOnLeft->right->right)
然后你可以打电话
DeleteDataPrivate(biggestOnLeft->data, biggestOnLeft->right);
免责声明:我没有对此进行测试,可能会输错字。
答案 1 :(得分:-2)
您不能通过引用TNode为指针指定NULL,因为引用变量不能为NULL。请参阅C++ pass pointer by reference and assign default value