问题
I wrote this and somehow it's ending up deleting all my left side on the tree not only the most left leaf.
I can't find my mistake, can someone help?
struct Node *delMin(struct Node **root)
{
struct Node *current = *root;
struct Node *b4Current;
while ((current->m_ls) == NULL) {
b4Current = current;
current = current->m_ls;
}
if ((current->m_rs) == NULL) {
b4Current->m_ls = 0;
free(current);
} else {
b4Current->m_ls = current->m_rs;
free(current);
}
return *root;
}
回答1:
Let's look at your function.
struct Node *delMin(struct Node **root)
You take a pointer to node pointer as argument and return the new head. That is unnecessary. Returning the head is only useful if it isn't updated otherwise. Your pointer-to-node-pointer approach caters for that (well, it should, but it doesn't), so that the return value is free for other information.
struct Node *b4Current;
Here, you define an uninitialised pointer. You should initialise it to NULL
to idicate that the current node, the head, doesn't have a parent. Otherwise the pointer will be a garbage value that is likely to cause undefined behaviour.
while ((current->m_ls) == NULL) {
b4Current = current;
current = current->m_ls;
}
Here, your condition is wrong: You want to go left as long as there is a pointer, but you do something else: You go left if there isn't anywhere to go! When the head has a left child, current
will stay at the head. Otherwise, it will be NULL
, which will cause havoc when you try to dereference it later.
if ((current->m_rs) == NULL) {
b4Current->m_ls = 0;
free(current);
} else {
b4Current->m_ls = current->m_rs;
free(current);
}
The two branches of the if
are really the same, if you think about. It's a bit like saying: if (x == 0) y = 0; else y = x;
.
But you need an if
here, namely to distinguish between the case that current
is the head or not. In the former case, you should update *head
, the latter case is what you have already written.
You should also catch the case that you can't remove a node from an empty list.
So:
void delMin(struct Node **root)
{
struct Node *current = *root;
struct Node *b4Current = NULL;
if (current == NULL) return NULL;
while (current->m_ls != NULL) {
b4Current = current;
current = current->m_ls;
}
if (b4Current == NULL) {
*root = current->m_rs;
} else {
b4Current->m_ls = current->m_rs;
}
free(current);
}
But since you are passing a pointer to your head node anyways, you could simplify the function to:
void delMin(struct Node **root)
{
if (*root == NULL) return;
while ((*root)->m_ls != NULL) {
root = &(*root)->m_ls;
}
struct Node *old = *root;
(*root) = (*root)->m_rs;
free(old);
}
You may have some ugly (*root)
s here, but you do away with a lot of auxiliary variables and if
statements. The idea is that you add one level of indirection by iterating with a pointer to node pointer. *root
takes the role of your b4Current
and (*root)->m_ls
is your current
, except that *root
starts with a sensible initial value, namely the root node.
回答2:
I believe your problem is in your while loop condition. You want to be traversing the left side of the tree while current->m_ls != NULL, otherwise you will delete the entire left side of you tree.
来源:https://stackoverflow.com/questions/30219315/deleting-the-lowest-value-in-a-binary-search-tree