我认为我的代码中存在多个错误,用于从BST中删除节点。我只是弄不清楚是什么!这是我的代码。提前谢谢!
void del(int val){
help = root;
f = help;
while (help){
if(help->data==val) break;
f = help;
if (val > help-> data) help = help->right;
else help = help->left;
} if(help->data != val) printf("\nElement not found!");
else{
printf("Element found!");
target = help;
if(val>f->data){
if(target->right && !target->left) {f->right = target->right; f = target->right;}
else {f->right = target->left; f = target->left;}
} else{
if(target->right && !target->left) {f->left = target->right; f = target->right;}
else {f->left = target->left; f = target->left;}
}
while(help ->right) help = help->right;
if(help->left) help = help->left;
f->right = help;
free(target);
}
}
答案 0 :(得分:0)
我发现的一个错误是,如果要删除树中的左节点,那么最后几行可能不起作用,因为它们不对称。所以,让我们说,树的根为6,左子为4,右子为8.现在,你要删除4.所以,在第一个while子句中找到节点之后,你会命中“if(val> f-> data){”的else子句。此时,f将指向6,目标和帮助将指向4.现在,您将f的左侧设置为目标的右侧,因此6的左侧将指向NULL并且f本身将指向NULL。到现在为止还挺好!但是,一旦你进入while循环,由于help没有正确的节点,help会继续指向6.最后,你创建f的正确节点(btw,f此时已经是NULL)来帮助和你真的会崩溃!
while (help->right)
help = help->right;
if (help->left)
help = help->left;
f->right = help;
另一个错误是您没有更新根指针,因此最终会删除根节点。
一种更简单的方法是将其分为三种情况。我正在为这三种情况提供代码。对这三种情况中的每一种使用样本树,然后对其进行调试/测试。
首先,如果找到的节点(你的文件循环正在进行)没有子节点,那么删除它并将其父节点设置为NULL并完成。这是第一个案例的粗略剪辑:
/* If the node has no children */
if (!help->left && !help->right) {
printf("Deleting a leaf node \n");
f = help->parent;
if (f) {
if (value > f->value)
f->right = NULL;
else
f->left = NULL;
}
/* If deleting the root itself */
if (f->value == root) {
root = NULL;
}
free(help);
return 0;
}
其次,如果找到的节点只有子节点(左或右),则将其拼接出来,找到的节点的子节点变为父节点的子节点。这是第二种情况:
/* If the node has only one child node */
if ((help->left && !help->right)
|| (!help->left && help->right)) {
printf("Deleting a node with only one child \n");
f = help->parent;
if (help->left) {
child_node = help->left;
} else {
child_node = help->right;
}
if (f) {
if (value > f->value) {
f->right = child_node;
} else {
f->left = child_node;
}
} else {
/* This must be the root */
root = child_node;
}
free(help);
return 0;
}
第三种情况很棘手 - 这里找到的节点有两个子节点。在这种情况下,您需要找到节点的后继节点,然后用后继节点替换找到的节点的值,然后删除后继节点。这是第三种情况:
/* If the node has both children */
if (help->left && help->right) {
successor_found = find_successor(help, help->data);
printf("Deleting a node with both children \n");
if (successor_found) {
successor_value = successor_found->value;
del(successor_found->value);
help->value = successor_value;
}
return 0;
}
而且,这是寻找继任者的代码:
binary_node_t *node find_successor(binary_node_t *node, int value) {
binary_node_t *node_found;
if (!node) {return NULL; }
node_found = node;
old_data = node->data;
/* If the node has a right sub-tree, get the min from the right sub-tree */
if (node->right != NULL) {
node = node->right;
while (node) {
node_found = node;
node = node->left;
}
return node_found;
}
/* If no right sub-tree, get the min from one of its ancestors */
while (node && node->data <= old_data) {
node = node->parent;
}
return (node);
}
答案 1 :(得分:0)
typedef struct xxx {
struct xxx *left;
struct xxx *right;
int data;
} ;
#define NULL (void*)0
#define FREE(p) (void)(p)
void treeDeleteNode1 (struct xxx **tree, int data)
{
struct xxx *del,*sub;
/* Find the place where node should be */
for ( ; del = *tree; tree = (data < del->data) ? &del->left : &del->right ) {
if (del->data == data) break;
}
/* not found: nothing to do */
if ( !*tree) return;
/* When we get here, `*tree` points to the pointer that points to the node_to_be_deleted
** If any of its subtrees is NULL, the other will become the new root
** ,replacing the deleted node..
*/
if ( !del->left) { *tree = del->right; FREE(del); return; }
if ( !del->right) { *tree = del->left; FREE(del); return; }
/* Both subtrees non-empty:
** Pick one (the left) subchain , save it, and set it to NULL */
sub = del->left;
del->left = NULL;
/* Find leftmost subtree of right subtree of 'tree' */
for (tree = &del->right; *tree; tree = &(*tree)->left) {;}
/* and put the remainder there */
*tree = sub;
FREE(del);
}
被称为:
...
struct xxx *root;
...
treeDeleteNode1( &root, 42);
...