I think there are multiple errors in my code for deleting a node from a BST. I just can't figure out what! Here's my code. Thanks in advance!
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);
}
}
One error that I spot is that if one were to delete the left node in the tree, then the last few lines might not work since they are not symmetric. So, let us say, the tree has root as 6 and left-child as 4 and right-child as 8. Now, you want to delete 4. So, after you have found the node in the first while clause, you would hit the else clause of "if (val > f->data){". At this point, f would point to 6, target and help would point to 4. Now, you are setting the left of f to right of target, so left of 6 would point to NULL and f itself would point to NULL. So, far so good! But, once you get into the while loop, since help has no right node, help would continue to point to 6. In the end, you make the right node of f (btw, f is already NULL at this point) to help and you would actually end up crashing!
while (help->right)
help = help->right;
if (help->left)
help = help->left;
f->right = help;
Another error is that you do not update the root pointer, incase you end up deleting the root node.
One simpler approach would be to divide this into three cases. I am providing code for all the three cases. Use a sample tree for each of these three cases and then debug/test it.
First, if the found node (which your file while loop is doing) has no child nodes, then delete it and set its parent to NULL and you are done. Here is a rough-first cut of the first case:
/* 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;
}
Second, if the found node has only child (left or right), then splice it out and the child of the found node becomes hte child of the parent node. Here is the second case:
/* 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;
}
The third case is tricky -- here the found node has two child nodes. In this case, you need to find the successor of the node and then replace the value of the found node with the successor node and then delete the successor node. Here is the third case:
/* 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;
}
And, here is the code to find successor:
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);
}
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);
}
To be called like:
...
struct xxx *root;
...
treeDeleteNode1( &root, 42);
...
Related
Im looking for iterative non-stack based (due to memory constraints, and minimal refactoring) kd-tree insertion only.
I have an entire kd-tree library working in C, functions (insert ,read, update, delete, knn search, rebalancing) I started to replace all recursive functions with iterative ones.
However, I noticed that my insertion was not working for some test data. Meaning actually the search could not find the inserted nodes when using iterative implementation but all data was found when using recursive implementation, , therefore, the bug is in iterative insert version.
node structure:
typedef struct kd_tree_node
{
struct kd_tree_node* left;
struct kd_tree_node* right;
struct kd_tree_node* parent;
float* dataset;
float distance_to_neighbor;
} kd_tree_node;
Below is an iterative insertion (i included parts directly related. No rebalacing logic, etc...):
void
kd_tree_add_record(kd_tree_node* root, const float data [], int depth,
const int k_dimensions,
const int copying, const float rebuild_threshold) {
/*rebalancing logic is NOT relevant, which I have NOT include, we can just build inefficient tree*/
/* is root empty? */
if (is_empty_node(root, k_dimensions)) {
root = kd_tree_new_node(data, k_dimensions, copying);
/*was the root set before*/
if (is_empty_node(kd_tree_get_root(), k_dimensions)) {
kd_tree_set_root(root);
}
} else {
/*iteratively insert new node*/
current = kd_tree_get_root();
/*while current is NOT null*/
while (!is_empty_node(current, k_dimensions)) {
parent = current;
/* Calculate current dimension (cd) of comparison */
cd = depth % k_dimensions;
/*determine current dimension/*/
/*by using modula operator we can cycle through all dimensions */
/* and decide the left or right subtree*/
median = kd_tree_get_column_median(cd);
//printf("kd_tree_add_record.(), median=%f\n",median);
if (data[cd] < median) {
current = current->left;
} else {
current = current->right;
}
depth++;
}//end while
/*should be inserted left or right of the parent*/
int insert_left = 1;
depth = 0;
if (!is_empty_node(parent,k_dimensions)) {
int c = 0;
for (; c < k_dimensions; c++) {
cd = depth % k_dimensions;
median = kd_tree_get_column_median(cd);
if (parent->dataset[cd] < median) {
} else {
insert_left = 0;
break;
}
depth++;
}
if (insert_left)
{
parent->left = kd_tree_new_node(data, k_dimensions, copying);
}
else
{
parent->right = kd_tree_new_node(data, k_dimensions, copying);
}
}
}//end else
}
I based my iterative kd-tree insert above code, by attempting to follow the iterative binary tree insert C++ code from: (https://www.techiedelight.com/insertion-in-bst/) which can be tested online, see below(note this not my code and its provided as reference):
void insertIterative(Node*& root, int key)
{
// start with root node
Node *curr = root;
// pointer to store parent node of current node
Node *parent = nullptr;
// if tree is empty, create a new node and set root
if (root == nullptr)
{
root = newNode(key);
return;
}
// traverse the tree and find parent node of key
while (curr != nullptr)
{
// update parent node as current node
parent = curr;
// if given key is less than the current node, go to left subtree
// else go to right subtree
if (key < curr->data)
curr = curr->left;
else
curr = curr->right;
}
// construct a new node and assign to appropriate parent pointer
if (key < parent->data)
parent->left = newNode(key);
else
parent->right = newNode(key);
}
Here is my previous kd-tree recursive insertion version, which works:
kd_tree_node *
kd_tree_add_record(kd_tree_node * root,
const float data[], int depth,
const int k_dimensions,
const int copying,
const float rebuild_threshold) {
float median = 0.0;
/* Tree is empty? */
if (NULL == root || NULL == root -> dataset || is_empty_node(root, k_dimensions)) {
root = kd_tree_new_node(data, k_dimensions, copying);
//update the root globally
if (kd_tree_get_root() == NULL) {
kd_tree_set_root(root);
}
} else {
/* Calculate current dimension (cd) of comparison */
size_t cd = depth % k_dimensions;
/*determine current dimension/*/
/*by using modula operator we can cycle through all dimensions */
/* and decide the left or right subtree*/
median = kd_tree_get_column_median(cd);
if (data[cd] < median) {
root -> left = kd_tree_add_record(root -> left, data, depth + 1,
k_dimensions,
copying, rebuild_threshold);
} else {
root -> right = kd_tree_add_record(root -> right, data, depth + 1,
k_dimensions,
copying, rebuild_threshold);
}
} //end else
return root;
}
current test results:
-53.148998,0.000000,9.000000 Found
7.999700,0.069812,8.000000 Found
7.998780,0.139619,8.000000 Found
7.997260,0.209416,8.000000 Not Found!
7.995130,0.279196,8.000000 Not Found!
7.992390,0.348955,8.000000 Not Found!
8.987670,0.471024,9.000000 Found
8.983210,0.549437,9.000000 Found
7.980510,0.558052,8.000000 Not Found!
3.000000,3.000000,3.000000 Found
4.000000,4.000000,4.000000 Found
5.000000,5.000000,5.000000 Found!
100.000000,100.000000,100.000000 Found
How can I extend the iterative non-stack binary insert algorithm to kd-trees?
Really appreciated!
I am trying to write a recursive function that, given the root of a binary tree and a key, searches for the key using in-order traversal. The function returns NULL if the node with the key isn't found; otherwise it returns the node containing the key.
What I'm having trouble with is returning the node that contains the key. Every time I call the function and the key is in the binary tree, the function returns NULL. It feels like the result keeps getting overwritten by the initialization in the first line in the function.
Here's the in-order search function:
typedef struct treeNode
{
int data;
struct treeNode *left, *right;
} TreeNode, *TreeNodePtr;
typedef struct
{
TreeNodePtr root;
} BinaryTree;
TreeNodePtr inOrderKey(TreeNodePtr root, int key)
{
TreeNodePtr node = NULL;
if (root != NULL)
{
node = inOrderKey(root->left, key);
if(key == root->data)
{
node = root;
return node;
}
node = inOrderKey(root->right, key);
}
return node;
}
Here's the main function:
int main()
{
FILE * in = fopen("numbst.txt", "r");
BinaryTree bst;
bst.root = NULL;
int num;
fscanf(in, "%d", &num);
while (num != 0)
{
if (bst.root == NULL)
bst.root = newTreeNode(num);
else
{
TreeNodePtr node = findOrInsert(bst, num);
}
fscanf(in, "%d", &num);
}
printf("\nThe in-order traversal is: ");
inOrder(bst.root);
printf("\nThe pre-order traversal is: ");
preOrder(bst.root);
TreeNodePtr keyNode;
int count = 0;
keyNode = inOrderKey(bst.root, 9);
if (keyNode != NULL)
count = 1;
else
count = 0;
if (count == 1)
printf("\n\n%d exists in the binary tree. In order traversal was used.\n", 9);
else
printf("\n\n%d doesn't exist in the binary tree. In order traversal was used.\n", 9);
return 0;
}
The in-order traversal of the binary tree I'm working with is: 1 2 3 4 5 7 9 21
The pre-order traversal of the binary tree is: 4 1 2 3 7 5 21 9
I'm testing the function using 9 and 31.
This code:
node = inOrderKey(root->left, key);
if(key == root->data)
{
node = root;
return node;
}
node = inOrderKey(root->right, key);
first uses inOrderKey to search the left subtree. Then it ignores the result.
Then it tests whether the current node contains the key. If it does, it returns to its caller. If the caller was itself (this is in a recursive call, not the original), the caller likely ignores the result.
Then it uses inOrderKey to search the right tree. Then it returns the result.]
Ultimately, the node containing the key will be returned only if it was in the rightmost path. If it is in the left subtree of any node, it will be ignored.
To fix this, after each call to inOrderKey, test whether the returned value is a null pointer. If it is not, return it immediately instead of going on.
The problem you have is that you insist in navigating the whole tree without checking if you found the key already. In
TreeNodePtr inOrderKey(TreeNodePtr root, int key)
{
/* don't declare a local you don't know
* yet if you are going to use */
/* better to check the opposite */
if (root == NULL)
return NULL; /* no tree, nothing can be found */
TreeNodePtr node = inOrderKey(root->left, key);
if (node) return node; /* we found it in the left child */
if(key == root->data) { /* check here */
/* you found it in this node */
return root;
}
/* last chance, right child :) */
return inOrderKey(root->right, key);
}
the verifications are made, so this should work (I've not tested it, as you didn't post a complete and verifiable example, my apologies for that)
[edited - updated to use in order traversal]
Traverse left. If key not found, then check root, if key doesn't match, then recurse right.
TreeNodePtr inOrderKey(TreeNodePtr root, int key)
{
TreeNodePtr node = NULL;
if (root)
{
node = inOrderKey(root->left, key);
if (node) {
return node;
}
if (key == root->data)
{
return root;
}
node = inOrderKey(root->right, key);
}
return node;
}
I have pre-written code that I'm trying to wrap my head around:
int maxExtract(node **tree)
{
node *prev = NULL;
node *curr = *tree;
int ret;
if(curr == NULL)
{
printf("Tree is empty!\n");
exit(-1);
}
while( curr->right != NULL )
{
prev = curr;
curr = curr->right;
}
ret = curr->data;
if( prev != NULL )
prev->right = curr->left;
else if( curr == *tree )
*tree = curr->left;
free(curr);
return ret;
}
I understand everything except the else if (curr == *tree) condition. I think it's saying that if the max node ends up being the root. However, wouldn't you need to change more connections than that after the else if, like to connect the right and left side of the tree to this new root after extracting the old one?
I think it's saying that if the max node ends up being the root.
That is exactly what it means and, if that's the case, then there can be nothing in the right side of that node because, if there were, the maximum would be somewhere in that (right) sub-tree, not at the root.
So let's consider the tree where the root is the maximum (and A1/A2 are arbitrary sub-trees, including empty ones):
MAX
/
x
/ \
A1 A2
To extract the maximum value, what you want to be left with is simply:
x
/ \
A1 A2
So the operation you want to perform is to make x the new root of the tree - this is done with the line in your code:
*tree = curr->left;
I'd probably write it slightly differently to explicitly handle the disparate cases rather than relying on things happening or not happening depending on various decisions in the middle of the code. By that, I mean:
int maxExtract (node **tree) {
// Handle empty tree as error.
if (*tree == NULL) {
printf ("Tree is empty!\n");
exit (-1);
}
// Handle root is max, i.e., has no right subtree.
if ((*tree)->right == NULL) {
node *nodeToDelete = *tree; // Save root for deletion.
int retVal = nodeToDelete->data; // Get data to return.
*tree = nodeToDelete->left; // Set new root.
free (nodeToDelete); // Delete old root.
return retVal; // Return old root value.
}
// Locate max and its previous.
node *prev = *tree;
node *curr = (*tree)->right;
while (curr->right != NULL) {
prev = curr;
curr = curr->right;
}
// Max has no right sub-tree but it MAY have a left one
// which needs to be transferred as-is to the right of prev.
int retVal = curr->data; // Get data to return.
node *nodeToDelete = curr; // Save root for deletion.
prev->right = curr->left; // Transfer left sub-tree (or null).
free (nodeToDelete); // Delete old max.
return retVal; // Return old max value.
I'm attempting to write an implementation of a red-black tree for my own learning and I've been staring at this for a few days now.
Could anyone help me figure out how I can get the double rotation cases to work correctly? If you spot anything else that sucks while you're looking through the snippets, feel free to make me feel like an idiot.
Your help is appreciated.
Rebalancing Function
int impl_rbtree_rebalance (xs_rbtree_node *node)
{
check_mem(node);
xs_rbtree_node *p = node->parent;
if (!p) return 0;
if (p->color == BLACK) return 0;
xs_rbtree_node *gp = p->parent;
if (!gp) return 0;
xs_rbtree_node *uncle;
int is_parent_left_child;
/* check if parent is left or right child */
if (p == gp->left) {
uncle = gp->right;
is_parent_left_child = 1;
} else {
uncle = gp->left;
is_parent_left_child = 0;
}
if (uncle && uncle->color == RED) {
p->color = uncle->color = BLACK;
gp->color = RED;
} else { /* uncle is black */
if (gp->parent == NULL) return 0;
if (node == p->left) {
if (is_parent_left_child == 0) {
/* Double rotation logic */
} else {/* parent is left child */
gp->color = RED;
gp->left->color = BLACK;
impl_rbtree_rr(&gp);
}
} else { /* node is right child */
if (is_parent_left_child == 1) {
/* Double rotation logic */
} else { /* parent is right child */
gp->color = RED;
gp->right->color = BLACK;
impl_rbtree_rl(&gp);
}
}
}
return 0;
}
Relevant Functions
xs_rbtree_node *impl_rbtree_node_alloc (xs_rbtree_node *parent, void *val)
{
xs_rbtree_node *n = malloc(sizeof(xs_rbtree_node));
n->parent = parent;
n->val = val;
n->left = n->right = NULL;
n->color = (parent == NULL) ? BLACK : RED;
return n;
}
void rbtree_insert (xs_rbtree_ *tree, void *val)
{
check_mem(tree);
check_mem(val);
tree->root = impl_rbtree_insert(tree->cmp, NULL, tree->root, val);
tree->root->color = BLACK;
}
xs_rbtree_node *impl_rbtree_insert (xs_tree_cmp cmp, xs_rbtree_node *parent, xs_rbtree_node *node, void *val)
{
check_mem(cmp);
check_mem(val);
if (!node) {
node = impl_rbtree_node_alloc(parent, val);
} else if (cmp(node->val, val) < 0) {
/* node->val < val */
check_mem(node);
node->right = impl_rbtree_insert(cmp, node, node->right, val);
impl_rbtree_rebalance(node->right);
} else if (cmp(node->val, val) > 0) {
/* node->val > val */
check_mem(node);
node->left = impl_rbtree_insert(cmp, node, node->left, val);
impl_rbtree_rebalance(node->left);
}
/* ignoring values that are equal */
return node;
}
Rotation Functions
#include <xs/base/bstree.h>
void impl_tree_rr(xs_tree_node **node)
{
check_mem(*node);
check_mem((*node)->left);
xs_tree_node *k1, *k2;
k2 = *node;
k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k1->parent = k2->parent;
k2->parent = k1;
*node = k1;
}
void impl_tree_rl(xs_tree_node **node)
{
check_mem(*node);
check_mem((*node)->right);
xs_tree_node *k1, *k2;
k2 = *node;
k1 = k2->right;
k2->right = k1->left;
k1->left = k2;
k1->parent = k2->parent;
k2->parent = k1;
*node = k1;
}
void impl_tree_drr(xs_tree_node **node)
{
check_mem(*node);
impl_tree_rl(&((*node)->left));
impl_tree_rr(node);
}
void impl_tree_drl(xs_tree_node **node)
{
check_mem(*node);
impl_tree_rr(&((*node)->right));
impl_tree_rl(node);
}
RBT Definitions
typedef struct xs_rbtree_node xs_rbtree_node;
typedef struct xs_rbtree_ xs_rbtree_;
typedef enum { RED, BLACK } impl_rbtree_color;
struct xs_rbtree_node {
xs_rbtree_node *left;
xs_rbtree_node *right;
xs_rbtree_node *parent;
void *val;
impl_rbtree_color color;
};
struct xs_rbtree_ {
xs_rbtree_node *root;
xs_tree_cmp cmp;
};
Double rotation is kind of tricky in Red Black trees when compared to AVL trees, the reason being the existence of parent pointers which exist in RB trees.
While we rotate the trees we need to adjust the parent pointers too.
I will to demonstrate it with an example. The tree below is the initial tree
20
/ \
10 30
/ \
3 15
/ \
12 18
And here goes the right rotated one
10
/ \
3 20
/ \
15 30
/ \
12 18
We observe 2 things there.
1. The root got changed.
2. The parent pointers for 3 nodes got changed ( 10, 20, 15 ) ie. for new root, old root and right child of new root. This will be true for
all right rotation cases. This is to make sure that that, the in order
traversal remains intact after rotation happens.
Now see how we rotate step by step.
public Node rotateRight() {
if(root.left == null) {
System.out.println("Cannot be rotated Right");
} else {
Node newRoot = root.left; // Assign new root.
Node orphaned = newRoot.right; // Store ref to the right child of new root.
newRoot.parent = root.parent; // new root parent point to old root parent.
root.parent = newRoot; // new root becomes parent of old root.
newRoot.right = root; // old root becomes right child of new root
root.left = orphaned;
if (orphaned != null) {
orphaned.parent = root;
}
root = newRoot;
}
return root;
}
Try doing this on paper couple of times, then it will look simpler.
Hope this helps.
Coming back to RB Trees. The above implementation will be applied to both the rotations we do in the balancing process. ( Let us take right right case)
When we have 3 generations of nodes, a grandfather, a father and a
child which got inserted.
1. When we have RR or LL config, do not swap colors
2. With RL and LR, we rotate the grandfather we swap the colour of grandpa and father, but when rotating the parent we do not try to swap
colours. Intent is just to bring them to RR or LL configs.
a. We need to see if the grandpa is right or left child of its
parent and assign the root accordingly.
b. If the grandpa has no parent means we are doing rotation at the level of tree's root, then we reassign the root of the tree.
Snippet for my implementation of RB tree.
temp is the new node which is added.
// if new node is the right child AND parent is right child
else if(temp.parent.right == temp && grandPa!=null && grandPa.right == temp.parent) {
// If becomes a right-right case
Boolean isLeft = isLeftChild(grandPa);
if(isLeft == null) {
// Grandpa has no parent, reassign root.
root = rotateLeft(grandPa,true);
}
else if(isLeft) {
grandPa.parent.left = rotateLeft(grandPa,true);
} else {
grandPa.parent.right = rotateLeft(grandPa,true);
}
}
refering to the question Deallocating binary-tree structure in C
struct Node{
Node *parent;
Node *next;
Node *child;
}
I tried to free a binary tree. The problem I have is the allocated objects are 5520 and the number of calls to the free functions is 2747. I don't know why, it should really free and iterate all over the nodes in the tree, here is the code that I use
int number_of_iterations =0;
int number_of_deletions =0;
void removetree(Node *node)
{
number_of_iterations++;
while(node != NULL)
{
Node *temp = node;
if(node->child != NULL)
{
node = node->child;
temp->child = node->next;
node->next = temp;
}
else
{
node = node->next;
remove(temp);
number_of_deletions++
}
}
}
Number of iteration is 5440 and the number of deletions is 2747.
New Fixed code: is that code correct ?
const Node *next(const Node *node)
{
if (node == NULL) return NULL;
if (node->child) return node->child;
while (node && node->next == NULL) {
node = node->parent;
}
if (node) return node->next;
return NULL;
}
for ( p= ctx->obj_root; p; p = next(p)) {
free(p);
}
If your nodes do indeed contain valid parent pointers, then the whole thing can be done in a much more compact and readable fashion
void removetree(Node *node)
{
while (node != NULL)
{
Node *next = node->child;
/* If child subtree exists, we have to delete that child subtree
first. Once the child subtree is gone, we'll be able to delete
this node. At this moment, if child subtree exists, don't delete
anything yet - just descend into the child subtree */
node->child = NULL;
/* Setting child pointer to null at this early stage ensures that
when we emerge from child subtree back to this node again, we will
be aware of the fact that child subtree is gone */
if (next == NULL)
{ /* Child subtree does not exist - delete the current node,
and proceed to sibling node. If no sibling, the current
subtree is fully deleted - ascend to parent */
next = node->next != NULL ? node->next : node->parent;
remove(node); // or `free(node)`
}
node = next;
}
}
This is a binary tree! It's confusing people because of the names you have chosen, next is common in a linked list but the types are what matters and you have one node referencing exactly two identical nodes types and that's all that matters.
Taken from here: https://codegolf.stackexchange.com/a/489/15982 which you linked to. And I renamed left to child and right to next :)
void removetree(Node *root) {
struct Node * node = root;
struct Node * up = NULL;
while (node != NULL) {
if (node->child != NULL) {
struct Node * child = node->child;
node->child = up;
up = node;
node = child;
} else if (node->next != NULL) {
struct Node * next = node->next;
node->child = up;
node->next = NULL;
up = node;
node = next;
} else {
if (up == NULL) {
free(node);
node = NULL;
}
while (up != NULL) {
free(node);
if (up->next != NULL) {
node = up->next;
up->next = NULL;
break;
} else {
node = up;
up = up->child;
}
}
}
}
}
I know that this is an old post, but i hope my answer helps someone in the future.
Here is my implementation of BinaryTree and it's operations in c++ without recursion, the logics can be easily implemented in C.
Each node owns a pointer to the parent node to make things easier.
NOTE: the inorderPrint() function used for printing out the tree's content uses recursion.
#include<iostream>
template<typename T>
class BinaryTree
{
struct node
{
//the binary tree node consists of a parent node for making things easier as you'll see below
node(T t)
{
value = t;
}
~node() { }
struct node *parent = nullptr;
T value;
struct node *left = nullptr;
struct node *right = nullptr;
};
node* _root;
//gets inorder predecessor
node getMinimum(node* start)
{
while(start->left)
{
start = start->left;
}
return *start;
}
/*
this is the only code that uses recursion
to print the inorder traversal of the binary tree
*/
void inorderTraversal(node* rootNode)
{
if (rootNode)
{
inorderTraversal(rootNode->left);
std::cout << rootNode->value<<" ";
inorderTraversal(rootNode->right);
}
}
int count;
public:
int Count()
{
return count;
}
void Insert(T val)
{
count++;
node* tempRoot = _root;
if (_root == nullptr)
{
_root = new node(val);
_root->parent = nullptr;
}
else
{
while (tempRoot)
{
if (tempRoot->value < val)
{
if (tempRoot->right)
tempRoot = tempRoot->right;
else
{
tempRoot->right = new node(val );
tempRoot->right->parent = tempRoot;
break;
}
}
else if (tempRoot->value > val)
{
if (tempRoot->left)
tempRoot = tempRoot->left;
else
{
tempRoot->left = new node(val);
tempRoot->left->parent = tempRoot;
break;
}
}
else
{
std::cout<<"value already exists";
count--;
}
}
}
}
void inorderPrint()
{
inorderTraversal(_root);
std::cout <<std::endl;
}
void Delete(T val)
{
node *tempRoot = _root;
//find the node with the value first
while (tempRoot!= nullptr)
{
if (tempRoot->value == val)
{
break;
}
if (tempRoot->value > val)
{
tempRoot = tempRoot->left;
}
else
{
tempRoot = tempRoot->right;
}
}
//if such node is found then delete that node
if (tempRoot)
{
//if it contains both left and right child replace the current node's value with inorder predecessor
if (tempRoot->right && tempRoot->left)
{
node inordPred = getMinimum(tempRoot->right);
Delete(inordPred.value);
count++;
tempRoot->value = inordPred.value;
}
else if (tempRoot->right)
{
/*if it only contains right child, then get the current node's parent
* check if the current node is the parent's left child or right child
* replace the respective pointer of the parent with the right child of the current node
*
* finally change the child's parent to the new parent
*/
if (tempRoot->parent)
{
if (tempRoot->parent->right == tempRoot)
{
tempRoot->parent->right = tempRoot->right;
}
if (tempRoot->parent->left == tempRoot)
{
tempRoot->parent->left = tempRoot->right;
}
tempRoot->right->parent = tempRoot->parent;
}
else
{
//if there is no parent then it's a root node
//root node should point to the current node's child
_root = tempRoot->right;
_root->parent = nullptr;
delete tempRoot;
}
}
else if (tempRoot->left)
{
/*
* same logic as we've done for the right node
*/
if (tempRoot->parent)
{
if (tempRoot->parent->right == tempRoot)
{
tempRoot->parent->right = tempRoot->left;
}
if (tempRoot->parent->left == tempRoot)
{
tempRoot->parent->left = tempRoot->left;
}
tempRoot->left->parent =tempRoot->parent ;
}
else
{
_root = tempRoot->left;
_root->parent = nullptr;
delete tempRoot;
}
}
else
{
/*
* if it's a leaf node, then check which ptr (left or right) of the parent is pointing to
* the pointer to be deleted (tempRoot)
* then replace that pointer with a nullptr
* then delete the (tempRoot)
*/
if (tempRoot->parent)
{
if (tempRoot->parent->right == tempRoot)
{
tempRoot->parent->right = nullptr;
}
else if (tempRoot->parent->left == tempRoot)
{
tempRoot->parent->left = nullptr;
}
delete tempRoot;
}
else
{
//if the leaf node is a root node ,then delete it and set it to null
delete _root;
_root = nullptr;
}
}
count--;
}
else
{
std::cout << "No element found";
}
}
void freeTree()
{
//the output it produces will be that of a preorder traversal
std::cout << "freeing tree:";
node* end=_root;
node* parent=nullptr;
while (end)
{
//go to the node with least value
if (end->left)
end = end->left;
else if (end->right)
{
//if it's already at the least value, then check if it has a right sub tree
//if it does then set it as "end" ptr so that the loop will check for the least node in this subtree
end = end->right;
}
else
{
//if it's a leaf node then it should be deleted and it's parent's (left or right pointer )
//should be safely set to nullptr
//then end should be set to the parent pointer
//so that it we can repeat the process for all other nodes that's left
std::cout << end->value<<" ";
parent = end->parent;
if (parent)
{
if (parent->left == end)
parent->left = nullptr;
else
parent->right = nullptr;
delete end;
}
else
{
delete end;
_root = nullptr;
}
count--;
end = parent;
}
}
}
~BinaryTree()
{
freeTree();
}
};
int main()
{
BinaryTree<int> bt;
bt.Insert(3);
bt.Insert(2);
bt.Insert(1);
bt.Insert(5);
bt.Insert(4);
bt.Insert(6);
std::cout << "before deletion:\n";
bt.inorderPrint();
bt.Delete(5);
bt.Delete(2);
bt.Delete(1);
bt.Delete(4);
std::cout << "after deletion:\n";
bt.inorderPrint();
bt.freeTree();
std::cout << "\nCount: " << bt.Count()<<"\n";
}
output:
before deletion:
1 2 3 4 5 6
after deletion:
3 6
freeing tree:6 3
Count: 0
freeing tree:
First to say is that if you try to solve a recursive problem in a non-recursive way, you'll run into trouble.
I have seen a wrong answer selected as the good one, so I'll try to show my approach:
I'll begin using pointer references instead of plain pointers, as passing a root pointer reference makes it easier to detect (and update) the pointers to the root node. So the interface to the routine will be:
void delete_tree(struct node * * const ref);
It represents a reference to the pointer that points to the root node. I'll descend to the node and, if one of child or next is NULL then this node can be freely eliminated by just making the referenced pointer to point to the other link (so I'll not lose it). If the node has two children (child and next are both != NULL) then I cannot delete this node until one of the branches has collapsed, and then I select one of the branches and move the reference (I declared the ref parameter const to assure I don't modify it, so I use another moving reference for this)
struct node **moving_reference;
Then, the algorithm follows:
void tree_delete(struct node ** const static_ref)
{
while (*static_ref) {
struct node **moving_ref = static_ref;
while (*moving_ref) {
struct node *to_be_deleted = NULL;
if ((*moving_ref)->child && (*moving_ref)->next) {
/* we have both children, we cannot delete until
* ulterior pass. Just move the reference. */
moving_ref = &(*moving_ref)->child;
} else if ((*moving_ref)->child) {
/* not both != NULL and child != NULL,
* so next == NULL */
to_be_deleted = *moving_ref;
*moving_ref = to_be_deleted->child;
} else {
/* not both != NULL and child == NULL,
* so follow next */
to_be_deleted = *moving_ref;
*moving_ref = to_be_deleted->next;
} /* if, else if */
/* now, delete the unlinked node, if available */
if (to_be_deleted) node_delete(to_be_deleted);
} /* while (*moving_ref) */
} /* while (*static_ref) */
} /* delete_tree */
I have included this algorithm in a complete example, showing you the partial trees and the position of moving_ref as it moves through the tree. It also shows the passes needed to delete it.
#include <stdio.h>
#include <stdlib.h>
#define N 100
#define D(x) __FILE__":%d:%s: " x, __LINE__, __func__
#define ASSERT(x) do { \
int res; \
printf(D("ASSERT: (" #x ") ==> %s\n"), \
(res = (int)(x)) ? "TRUE" : "FALSE"); \
if (!res) exit(EXIT_FAILURE); \
} while (0)
struct node {
int key;
struct node *child;
struct node *next;
}; /* struct node */
struct node *node_alloc(void);
void node_delete(struct node *n);
/* This routine has been written recursively to show the simplicity
* of traversing the tree when you can use recursive algorithms. */
void tree_traverse(struct node *n, struct node *p, int lvl)
{
while(n) {
printf(D("%*s[%d]\n"), lvl<<2, p && p == n ? ">" : "", n->key);
tree_traverse(n->child, p, lvl+1);
n = n->next;
} /* while */
} /* tree_traverse */
void tree_delete(struct node ** const static_ref)
{
int pass;
printf(D("BEGIN\n"));
for (pass = 1; *static_ref; pass++) {
struct node **moving_ref = static_ref;
printf(D("Pass #%d: Considering node %d:\n"),
pass, (*moving_ref)->key);
while (*moving_ref) {
struct node *to_be_deleted = NULL;
/* print the tree before deciding what to do. */
tree_traverse(*static_ref, *moving_ref, 0);
if ((*moving_ref)->child && (*moving_ref)->next) {
printf(D("Cannot remove, Node [%d] has both children, "
"skip to 'child'\n"),
(*moving_ref)->key);
/* we have both children, we cannot delete until
* ulterior pass. Just move the reference. */
moving_ref = &(*moving_ref)->child;
} else if ((*moving_ref)->child) {
/* not both != NULL and child != NULL,
* so next == NULL */
to_be_deleted = *moving_ref;
printf(D("Deleting [%d], link through 'child' pointer\n"),
to_be_deleted->key);
*moving_ref = to_be_deleted->child;
} else {
/* not both != NULL and child != NULL,
* so follow next */
to_be_deleted = *moving_ref;
printf(D("Deleting [%d], link through 'next' pointer\n"),
to_be_deleted->key);
*moving_ref = to_be_deleted->next;
} /* if, else if */
/* now, delete the unlinked node, if available */
if (to_be_deleted) node_delete(to_be_deleted);
} /* while (*moving_ref) */
printf(D("Pass #%d end.\n"), pass);
} /* for */
printf(D("END.\n"));
} /* delete_tree */
struct node heap[N] = {0};
size_t allocated = 0;
size_t deleted = 0;
/* simple allocation/free routines, normally use malloc(3). */
struct node *node_alloc()
{
return heap + allocated++;
} /* node_alloc */
void node_delete(struct node *n)
{
if (n->key == -1) {
fprintf(stderr,
D("doubly freed node %ld\n"),
(n - heap));
}
n->key = -1;
n->child = n->next = NULL;
deleted++;
} /* node_delete */
/* main simulation program. */
int main()
{
size_t i;
printf(D("Allocating %d nodes...\n"), N);
for (i = 0; i < N; i++) {
struct node *n;
n = node_alloc(); /* the node */
n->key = i;
n->next = NULL;
n->child = NULL;
printf(D("Node %d"), n->key);
if (i) { /* when we have more than one node */
/* get a parent for it. */
struct node *p = heap + (rand() % i);
printf(", parent %d", p->key);
/* insert as a child of the parent */
n->next = p->child;
p->child = n;
} /* if */
printf("\n");
} /* for */
struct node *root = heap;
ASSERT(allocated == N);
ASSERT(deleted == 0);
printf(D("Complete tree:\n"));
tree_traverse(root, NULL, 0);
tree_delete(&root);
ASSERT(allocated == N);
ASSERT(deleted == N);
} /* main */
Why not just do this recurisively?
void removetree(Node *node) {
if (node == NULL) {
return;
}
number_of_iterations++;
removetree(node->next);
removetree(node->child);
free(node);
number_of_deletions++;
}
The implementation does not work for a tree with root 1, which has a single child 2.
NodeOne.parent = null
NodeOne.next = null
NodeOne.child = NodeTwo
NodeTwo.parent = null
NodeTwo.next = null
NodeTwo.child = null
Execution of Removetree(NodeOne) will not call remove on NodeOne.
I would do
void removeTree(Node *node){
Node *temp;
while (node !=NULL){
if (node->child != NULL) {
removeTree(node->child);
}
temp = node;
node = node->next;
free(temp);
}
}
Non-recursive version:
void removeTree(Node *node){
Node *temp;
while (node !=NULL){
temp = node;
while(temp != node) {
for(;temp->child == NULL; temp = temp->child); //Go to the leaf
if (temp->next == NULL)
free(temp); //free the leaf
else { // If there is a next move it to the child an repeat
temp->child = temp->next;
temp->next = temp->next->next;
}
}
node = temp->next; // Move to the next
free(temp)
}
}
I think this should work
You are freeing only subtrees, not parent nodes. Suppose child represents the left child of the node and next is the right child. Then, your code becomes:
struct Node{
Node *parent;
Node *right;
Node *left;
}
int number_of_iterations =0;
int number_of_deletions =0;
void removetree(Node *node)
{
number_of_iterations++;
while(node != NULL)
{
Node *temp = node;
if(node->left != NULL)
{
node = node->left;
temp->left = node->right;
node->right = temp;
}
else
{
node = node->right;
remove(temp);
number_of_deletions++
}
}
}
Each time your while loop finishes one iteration, a left sub-node will be left without a pointer to it.
Take, for example the following tree:
1
2 3
4 5 6 7
When node is the root node, the following happens
node is pointing to '1'
temp is pointing to '1'
node now points to '2'
temp->left now points to '5'
node->right now points to '1'
In the next iteration, you begin with
node pointing to '2' and temp also. As you can see, you did not remove node '1'. This will repeat.
In order to fix this, you might want to consider using BFS and a queue-like structure to remove all the nodes if you want to avoid recursion.
Edit
BFS way:
Create a Queue structure Q
Add the root node node to Q
Add left node of node to Q
Add right node of node to Q
Free node and remove it from Q
Set node = first element of Q
Repeat steps 3-6 until Q becomes empty
This uses the fact that queue is a FIFO structure.
Code that was proposed by #AnT is incorrect, because it frees node right after traversing and freeing its left subtree but before doing the same with the right subtree. So, on ascending from the right subtree we'll step on the parent node that was already freed.
This is a correct approach, in C89. It still requires the parent links, though.
void igena_avl_subtree_free( igena_avl_node_p root ) {
igena_avl_node_p next_node;
{
while (root != NULL) {
if (root->left != NULL) {
next_node = root->left;
root->left = NULL;
} else if (root->right != NULL) {
next_node = root->right;
root->right = NULL;
} else {
next_node = root->parent;
free( root );
}
root = next_node;
}
}}
Taken directly from my own project Gena.