Я пишу код для назначения c++, это реализация словаря, использующая двоичное дерево поиска. Мой код компилируется, но когда я пытаюсь "удалить", я получаю seg Fault. любые идеи, почему это могло произойти. благодаря
Вот мой код
// 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;
}
}
EDIT:
Спасибо вам всем!! С вашего поста я понял, что было хорошей идеей проверить, был ли узел последним и детей не было. Я добавил эту проверку в deleteNode
if((nodePtr->left) && word < nodePtr->word)
{
do something
}
я сделал то же самое для правильной работы, и не делал никаких ошибок или сбоев. Спасибо!!!!
Случай 1: Пустое дерево:
Предположим, что ваше дерево пуст: root
будет nullptr
. Так deleteContent()
будем называть deleteNode()
с аргументом nullptr
для nodePtr
.
Первое, что вы есть сравнить word
с nodePtr->word
без первой проверки, что nodePtr
не nullptr
. У вас есть первый случай скрещивания!
Случай 2: удалите слово, которое не находится в дереве:
В этом случае deleteNode()
будет вызываться рекурсивно до тех пор, пока не достигнет листового узла без потомка. Поскольку искомое слово не существует в дереве, оно либо имеет значение, либо меньшее, чем nodePtr-> слово, но никогда не равнозначно. deleteNode()
будет называть себя, снова передавая аргумент nullptr
для nodePtr
, как и в случае 1. Опять же, вы будете иметь ошибку сегментации!
Решение в случае 1 и 2: управление nullptr в deleteNode():
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->word
. Избавьтесь от первого if(), которое в любом случае не должно быть истинным. Может быть заменено его утверждением при проверке инварианта.
Случай 3: Удалить слово в дереве:
Кажется, что все три случая работают (даже листовые узлы с двумя нулевыми указателями), по крайней мере, если я посмотрю на мой рисунок вашей структуры данных.
Однако я хотел бы предложить, чтобы проверить Node::~Node()
: во всех случаях, вы прикрутите ребенок, а затем удалить старый узел (temNodePtr
), не поставив свои ребенок nullptr
. Поэтому я задаюсь вопросом, просто ли ~Node()
просто разрушает узел, не заботясь о его дочерних makeDeletion()
(тогда makeDeletion()
должен работать) или если его рекурсивный деструктор, удалив узел и его дочерние makeDeletion()
тогда makeDeletion()
не будет работать, потому что вы удалит узлы, которые вы только что подключили, не заметив их, создав вначале seg.fault).
Кстати, nullptr может быть более подходящим, чем NULL для указателей, даже если NULL будет работать правильно.
nodePtr->word
, вы будете разыменовывать нулевой указатель.