AVL Tree unit test, get the height of nodes without parents - c

For my school assignment I have to implement an AVL tree node insertion. I have this unit test, with 4 tests, and 2 of them always fails.
I use two global variables, one Array to store the numbers and one integer for the index.
int pom = 0;
int test_output[1000];
The first 2 test checks the rotations with parents:
void test_right_rotation_with_parent() {
//Arrange
struct Node* root = NULL;
int insert_nodes[] = { 15,10,5 };
int correct_output[] = { 10,2,5,1,15,1 }; // node -> key, node -> height;
char* passed = PASSED;
//Act
for (int i = 0; i < 3; i++) {
insert(root, insert_nodes[i]);
}
preOrder(root);
//Assert
for (int i = 0; i < 6; i++) {
if (correct_output[i] != test_output[i]) {
passed = FAILED;
break;
}
}
printf("%s: %s\n", __func__, passed);
}
Output: test_right_rotation_with_parent: PASSED.
Same test for left rotation. Then I have 2 test for rotations without parents. These are the test which I cannot pass.
void test_right_rotation_without_parent() {
//Arrange
struct Node* root = NULL;
int insert_nodes[] = { 20,25,15,10,5 };
int correct_output[] = { 20,3,10,2,5,1,15,1,25,1 }; // node -> key, node -> height;
char* passed = PASSED;
//Act
for (int i = 0; i < 5; i++) {
insert(root, insert_nodes[i]);
}
preOrder(root);
...
}
Output: test_right_rotation_without_parent: FAILED
PreOrder:
void preOrder(struct Node *root) {
if (root != NULL) { // this is the main problem if a node hasn't got parent
test_output[pom++] = root->key;
test_output[pom++] = root->height;
preOrder(root->link[0]); // left side
preOrder(root->link[1]); // right side
}
}
And this is the part of the insert function, which creates a Node, if previously there wasn't any.
struct Node *insert(struct Node *node, int key)
{
if (node == NULL)
{
struct Node *node = malloc(sizeof *node);
if (node != NULL)
{
/* if I do the same thing here which I did in preOrder,
* the sequence of the keys will be correct,
* however the height will always be 1 (for the without parent functions) */
node->key = key;
node->height = 1;
node->link[0] = node->link[1] = NULL;
}
return node;
}
else {...}
Is it possible to make this work with this method? Or I need to find another method if I want to pass these test?

Related

How can I implement a check function to check the validity of the properties of a b-tree?

I have recently implemented a normal B-tree (without any variant) in C, but I would like to check if my implementation is valid i.e. if it does not violate the following properties:
Every node has at most m children.
Every non-leaf node (except root) has at least ⌈m/2⌉ child nodes.
The root has at least two children if it is not a leaf node.
A non-leaf node with k children contains k − 1 keys.
All leaves appear in the same level and carry no information.
Could help me with the implementation of this procedure giving me an example with some code in C or with some suggestions?
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define EMPTY 0
#define NODE_ORDER 3 /*The degree of the tree.*/
#define NODE_POINTERS (NODE_ORDER*2)
#define NODE_KEYS NODE_POINTERS-1
typedef unsigned char bool;
typedef struct tree_node {
int key_array[NODE_KEYS];
struct tree_node *child_array[NODE_POINTERS];
unsigned int key_index;
bool leaf;
} node_t;
typedef struct {
node_t *node_pointer;
int key;
bool found;
unsigned int depth;
} result_t;
typedef struct {
node_t *root;
unsigned short order;
bool lock;
} btree_t;
static int BTreeGetLeftMax(node_t *T);
static int BTreeGetRightMin(node_t *T);
/* The AllocateNode operation allocate a b-tree node.And then set the node's
** properties to the defualt value :
** BTreeNode => K[i] = 0
** BTreeNode => child_array[i] = NULL
** BTreeNode => key_index = 0
** BTreeNode => isLeaf = 1;
*/
static node_t *create_node()
{
int i;
node_t *new_node = (node_t *)malloc(sizeof(node_t));
if(!new_node){
printf("Out of memory");
exit(0);
}
// Set Keys
for(i = 0;i < NODE_KEYS; i++){
new_node->key_array[i] = 0;
}
// Set ptr
for(i = 0;i < NODE_POINTERS; i++){
new_node->child_array[i] = NULL;
}
new_node->key_index = EMPTY;
new_node->leaf = TRUE;
return new_node;
}
/* The CreatBTree operation creates an empty b-tree by allocating a new root
** that has no keys and is a leaf node.Only the root node is permitted to
** have this properties.
*/
btree_t *create_btree()
{
btree_t *new_root = (btree_t *)malloc(sizeof(btree_t));
if(!new_root){
return NULL;
}
node_t *head = create_node();
if(!head){
return NULL;
}
new_root->order = NODE_ORDER;
new_root->root = head;
new_root->lock = FALSE;
return new_root;
}
static result_t *get_resultset()
{
result_t *ret = (result_t *)malloc(sizeof(result_t));
if(!ret){
printf("ERROR! Out of memory.");
exit(0);
}
ret->node_pointer = NULL;
ret->key = 0;
ret->found = FALSE;
ret->depth = 0;
return ret;
}
/* The BTreeSearch operation is to search X in T.Recursively traverse the tree
** from top to bottom.At each level, BTreeSearch choose the maximum key whose
** value is greater than or equal to the desired value X.If equal to the
** desired ,found.Otherwise continue to traverse.
*/
result_t *search(int key, node_t *node)
{
print_node(node);
int i = 0;
while((i < node->key_index) && (key > node->key_array[i])){
//printf("it %d is <= %d and key %d > than %d\n", i, node->key_index, key, node->key_array[i]);
i++;
}
//printf("end iterator: %d\n", i);
//printf("better: \n");
/*
int c = 0;
while((c < node->key_index) && (key > node->key_array[c])){
printf("it %d is <= %d and key %d > than %d\n", c, node->key_index, key, node->key_array[c]);
c++;
}
*/
// HACK /// may not be working
if(i == 6){
i--;
}
// Check if we found it
if((i <= node->key_index) && (key == node->key_array[i])){
result_t *result = get_resultset();
result->node_pointer = node;
result->key = i;
result->found = TRUE;
return result;
}
// Not found check leaf or child
if(node->leaf){
result_t *result = get_resultset();
result->node_pointer = node;
result->found = FALSE;
return result;
}else{
result_t *result = get_resultset();
return search(key, node->child_array[i]);
}
}
/* The split_child operation moves the median key of node child_array into
** its parent ptrParent where child_array is the ith child of ptrParent.
*/
static void split_child(node_t *parent_node, int i, node_t *child_array)
{
int j;
//Allocate a new node to store child_array's node.
node_t *new_node = create_node();
new_node->leaf = child_array->leaf;
new_node->key_index = NODE_ORDER-1;
//Move child_array's right half nodes to the new node.
for(j = 0;j < NODE_ORDER-1;j++){
new_node->key_array[j] = child_array->key_array[NODE_ORDER+j];
}
//If child_array is not leaf node,then move child_array's [child_array]s to the new
//node's [child_array]s.
if(child_array->leaf == 0){
for(j = 0;j < NODE_ORDER;j++){
new_node->child_array[j] = child_array->child_array[NODE_ORDER+j];
}
}
child_array->key_index = NODE_ORDER-1;
//Right shift ptrParent's [child_array] from index i
for(j = parent_node->key_index;j>=i;j--){
parent_node->child_array[j+1] = parent_node->child_array[j];
}
//Set ptrParent's ith child_array to the newNode.
parent_node->child_array[i] = new_node;
//Right shift ptrParent's Keys from index i-1
for(j = parent_node->key_index;j>=i;j--){
parent_node->key_array[j] = parent_node->key_array[j-1];
}
//Set ptrParent's [i-1]th Key to child_array's median [child_array]
parent_node->key_array[i-1] = child_array->key_array[NODE_ORDER-1];
//Increase ptrParent's Key number.
parent_node->key_index++;
}
/* The BTreeInsertNonFull operation insert X into a non-full node T.before
** execute this operation,guarantee T is not a full node.
*/
static void insert_nonfull(node_t *n, int key){
int i = n->key_index;
if(n->leaf){
// Shift until we fit
while(i>=1 && key<n->key_array[i-1]){
n->key_array[i] = n->key_array[i-1];
i--;
}
n->key_array[i] = key;
n->key_index++;
}else{
// Find the position i to insert.
while(i>=1 && key<n->key_array[i-1]){
i--;
}
//If T's ith child_array is full,split first.
if(n->child_array[i]->key_index == NODE_KEYS){
split_child(n, i+1, n->child_array[i]);
if(key > n->key_array[i]){
i++;
}
}
//Recursive insert.
insert_nonfull(n->child_array[i], key);
}
}
/* The BTreeInsert operation insert key into T.Before insert ,this operation
** check whether T's root node is full(root->key_index == 2*d -1) or not.If full,
** execute split_child to guarantee the parent never become full.And then
** execute BTreeInsertNonFull to insert X into a non-full node.
*/
node_t *insert(int key, btree_t *b)
{
if(!b->lock){
node_t *root = b->root;
if(root->key_index == NODE_KEYS){ //If node root is full,split it.
node_t *newNode = create_node();
b->root = newNode; //Set the new node to T's Root.
newNode->leaf = 0;
newNode->key_index = 0;
newNode->child_array[0] = root;
split_child(newNode, 1, root);//Root is 1th child of newNode.
insert_nonfull(newNode, key); //Insert X into non-full node.
}else{ //If not full,just insert X in T.
insert_nonfull(b->root, key);
}
}else{
printf("Tree is locked\n");
}
return b->root;
}
/* The merge_children operation merge the root->K[index] and its two child
** and then set chlid1 to the new root.
*/
static void merge_children(node_t *root, int index, node_t *child1, node_t *child2){
child1->key_index = NODE_KEYS;
int i;
//Move child2's key to child1's right half.
for(i=NODE_ORDER;i<NODE_KEYS;i++)
child1->key_array[i] = child2->key_array[i-NODE_ORDER];
child1->key_array[NODE_ORDER-1] = root->key_array[index]; //Shift root->K[index] down.
//If child2 is not a leaf node,must copy child2's [ptrchlid] to the new
//root(child1)'s [child_array].
if(0 == child2->leaf){
for(i=NODE_ORDER;i<NODE_POINTERS;i++)
child1->child_array[i] = child2->child_array[i-NODE_ORDER];
}
//Now update the root.
for(i=index+1;i<root->key_index;i++){
root->key_array[i-1] = root->key_array[i];
root->child_array[i] = root->child_array[i+1];
}
root->key_index--;
free(child2);
}
/* The BTreeBorrowFromLeft operation borrows a key from leftPtr.curPtr borrow
** a node from leftPtr.root->K[index] shift down to curPtr,shift leftPtr's
** right-max key up to root->K[index].
*/
static void BTreeBorrowFromLeft(node_t *root, int index, node_t *leftPtr, node_t *curPtr){
curPtr->key_index++;
int i;
for(i=curPtr->key_index-1;i>0;i--)
curPtr->key_array[i] = curPtr->key_array[i-1];
curPtr->key_array[0] = root->key_array[index];
root->key_array[index] = leftPtr->key_array[leftPtr->key_index-1];
if(0 == leftPtr->leaf)
for(i=curPtr->key_index;i>0;i--)
curPtr->child_array[i] = curPtr->child_array[i-1];
curPtr->child_array[0] = leftPtr->child_array[leftPtr->key_index];
leftPtr->key_index--;
}
/* The BTreeBorrowFromLeft operation borrows a key from rightPtr.curPtr borrow
** a node from rightPtr.root->K[index] shift down to curPtr,shift RightPtr's
** left-min key up to root->K[index].
*/
static void BTreeBorrowFromRight(node_t *root, int index, node_t *rightPtr, node_t *curPtr){
curPtr->key_index++;
curPtr->key_array[curPtr->key_index-1] = root->key_array[index];
root->key_array[index] = rightPtr->key_array[0];
int i;
for(i=0;i<rightPtr->key_index-1;i++)
rightPtr->key_array[i] = rightPtr->key_array[i+1];
if(0 == rightPtr->leaf){
curPtr->child_array[curPtr->key_index] = rightPtr->child_array[0];
for(i=0;i<rightPtr->key_index;i++)
rightPtr->child_array[i] = rightPtr->child_array[i+1];
}
rightPtr->key_index--;
}
/* The BTreeDeleteNoNone operation recursively delete X in root,handle both leaf
** and internal node:
** 1. If X in a leaf node,just delete it.
** 2. If X in a internal node P:
** a): If P's left neighbor -> prePtr has at least d keys,replace X with
** prePtr's right-max key and then recursively delete it.
** b): If P's right neighbor -> nexPtr has at least d keys,replace X with
** nexPtr's left-min key and then recursively delete it.
** c): If both of prePtr and nexPtr have d-1 keys,merge X and nexPtr into
** prePtr.Now prePtr have 2*d-1 keys,and then recursively delete X in
** prePtr.
** 3. If X not in a internal node P,X must in P->child_array[i] zone.If child_array[i]
** only has d-1 keys:
** a): If child_array[i]'s neighbor have at least d keys,borrow a key from
** child_array[i]'s neighbor.
** b): If both of child_array[i]'s left and right neighbor have d-1 keys,merge
** child_array[i] with one of its neighbor.
** finally,recursively delete X.
*/
static void BTreeDeleteNoNone(int X, node_t *root){
int i;
//Is root is a leaf node ,just delete it.
if(1 == root->leaf){
i=0;
while( (i<root->key_index) && (X>root->key_array[i])) //Find the index of X.
i++;
//If exists or not.
if(X == root->key_array[i]){
for(;i<root->key_index-1;i++)
root->key_array[i] = root->key_array[i+1];
root->key_index--;
}
else{
printf("Node not found.\n");
return ;
}
}
else{ //X is in a internal node.
i = 0;
node_t *prePtr = NULL, *nexPtr = NULL;
//Find the index;
while( (i<root->key_index) && (X>root->key_array[i]) )
i++;
if( (i<root->key_index) && (X == root->key_array[i]) ){ //Find it in this level.
prePtr = root->child_array[i];
nexPtr = root->child_array[i+1];
/*If prePtr at least have d keys,replace X by X's precursor in
*prePtr*/
if(prePtr->key_index > NODE_ORDER-1){
int aPrecursor = BTreeGetLeftMax(prePtr);
root->key_array[i] = aPrecursor;
//Recursively delete aPrecursor in prePtr.
BTreeDeleteNoNone(aPrecursor,prePtr);
}
else
if(nexPtr->key_index > NODE_ORDER-1){
/*If nexPtr at least have d keys,replace X by X's successor in
* nexPtr*/
int aSuccessor = BTreeGetRightMin(nexPtr);
root->key_array[i] = aSuccessor;
BTreeDeleteNoNone(aSuccessor,nexPtr);
}
else{
/*If both of root's two child have d-1 keys,then merge root->K[i]
* and prePtr nexPtr. Recursively delete X in the prePtr.*/
merge_children(root,i,prePtr,nexPtr);
BTreeDeleteNoNone(X,prePtr);
}
}
else{ //Not find in this level,delete it in the next level.
prePtr = root->child_array[i];
node_t *leftBro = NULL;
if(i<root->key_index)
nexPtr = root->child_array[i+1];
if(i>0)
leftBro = root->child_array[i-1];
/*root->child_array[i] need to borrow from or merge with his neighbor
* and then recursively delete. */
if(NODE_ORDER-1 == prePtr->key_index){
//If left-neighbor have at least d-1 keys,borrow.
if( (leftBro != NULL) && (leftBro->key_index > NODE_ORDER-1))
BTreeBorrowFromLeft(root,i-1,leftBro,prePtr);
else //Borrow from right-neighbor
if( (nexPtr != NULL) && (nexPtr->key_index > NODE_ORDER-1))
BTreeBorrowFromRight(root,i,nexPtr,prePtr);
//OR,merge with its neighbor.
else if(leftBro != NULL){
//Merge with left-neighbor
merge_children(root,i-1,leftBro,prePtr);
prePtr = leftBro;
}
else //Merge with right-neighbor
merge_children(root,i,prePtr,nexPtr);
}
/*Now prePtr at least have d keys,just recursively delete X in
* prePtr*/
BTreeDeleteNoNone(X,prePtr);
}
}
}
/*Get T's left-max key*/
static int BTreeGetLeftMax(node_t *T){
if(0 == T->leaf){
return BTreeGetLeftMax(T->child_array[T->key_index]);
}else{
return T->key_array[T->key_index-1];
}
}
/*Get T's right-min key*/
static int BTreeGetRightMin(node_t *T){
if(0 == T->leaf){
return BTreeGetRightMin(T->child_array[0]);
}else{
return T->key_array[0];
}
}
/* The BTreeDelete operation delete X from T up-to-down and no-backtrack.
** Before delete,check if it's necessary to merge the root and its children
** to reduce the tree's height.Execute BTreeDeleteNoNone to recursively delete
*/
node_t *delete(int key, btree_t *b)
{
if(!b->lock){
//if the root of T only have 1 key and both of T's two child have d-1
//key,then merge the children and the root. Guarantee not need to backtrack.
if(b->root->key_index == 1){
node_t *child1 = b->root->child_array[0];
node_t *child2 = b->root->child_array[1];
if((!child1) && (!child2)){
if((NODE_ORDER-1 == child1->key_index) && (NODE_ORDER-1 == child2->key_index)){
//Merge the children and set child1 to the new root.
merge_children(b->root, 0, child1, child2);
free(b->root);
BTreeDeleteNoNone(key, child1);
return child1;
}
}
}
BTreeDeleteNoNone(key, b->root);
}else{
printf("Tree is locked\n");
}
return b->root;
}
void tree_unlock(btree_t *r)
{
r->lock = FALSE;
}
bool tree_lock(btree_t *r)
{
if(r->lock){
return FALSE;
}
r->lock = TRUE;
return TRUE;
}
You have not shown any code, which makes it difficult to come up with code examples that could fit to your implementation. However, in principle you could take the following approaches:
Write unit-tests for your code. With the B-Tree that would mean to start with small trees (even with an empty tree), and use checks in your tests to verify the properties. You would then add more and more tests, specifically checking for bugs also in the "tricky" scenarios. There is a lot of general information about unit-testing available, you should be able to adapt it to your specific problem.
Add assertions to your code (read about the assert macro in C). Many of the properties you have mentioned could be checked directly within the code at appropriate places.
Certainly, there is more you could do, like, having the code reviewed by some colleague, or using some formal verification tools, but the abovementioned two approaches are good starting points.
UPDATE (after code was added):
Some more hints about how you could approach unit-testing. In principle, you should write your tests with the help of a so called test framework, which is a helper library to make writing tests easier. To explain the concept, however, I just use plain C or even pseudo-code.
Moreover, you would also put some declarations and/or definitions into a header file, like "btree.h". For the sake of example, however, I will just #include "btree.c" in the code examples below.
Create a file "btree-test.c" (the name is a proposal, you can name it as you like).
A first test would look a bit like:
#include "btree.c"
#include <assert.h>
void test_create_empty_btree() {
btree_t *actual_btree = create_btree();
// now, check that the created btree has all desired properties
// for example:
assert(actual_btree != NULL);
assert(actual_btree->order == NODE_ORDER);
assert(actual_btree->lock == FALSE);
assert(actual_btree->root->key_index == EMPTY);
assert(actual_btree->root->leaf == TRUE);
printf("PASSED: test_create_empty_btree");
}
The code above is just an example, I have not even tried compiling it. Note also that the test is not quite clean yet: there will be memory leaks, because the btree is not properly deleted at the end of the test, which would be better practice. It should, however, give you an idea how to start writing unit-tests.
A second test could then again create a btree, but in addition insert some data. In your tests you would then check that the btree has the expected form. And so on, adding more and more tests. It is good practice to have one function per test case...

see get min value of nodes, exceptional case

Given the following struct:
typedef struct node_t {
int x;
struct node_t *next;
} *Node;
Please Note: the definition above is given to me as is and can't be changed.
I wrote the following function:
inline int getMin(Node *list1,Node *list2)
{
int first_value=INT_MAX,second_value=INT_MAX;
if (*list1)
{
first_value=(*list1)->x;
}
if (*list2)
{
second_value=(*list2)->x;
}
if (first_value<second_value)
{
*list1=(*list1)->next;
return first_value;
}
*list2=(*list2)->next;
return second_value;
}
It receives 2 pointers to a series of Nodes while each node has two attributes: x and next (a pointer to the next code)
My code should get the minimum value when comparing the values of the current two nodes, while it works fine with 99% of the cases it doesn't work with the case where list1 points to a node that its value is INT_MAX and next points to null and list2 is NULL
how can I fix this?
I fixed this by changing the following code:
if (first_value<second_value) to
if (first_value<=second_value)
but I have a new problem:
list2 points to a node that its value is INT_MAX and next points to null and list1 is NULL
Edit: Here is the last version of my code:
helper functions:
int advance(Node *node) {
int node_value = (*node)->x;
*node = (*node)->next;
return node_value;
}
int getMin(Node *list1, Node *list2) {
assert(*list1 || *list2);
if (!(*list1)) {
return advance(list2);
}
if (!(*list2)) {
return advance(list1);
}
if ((*list1)->x < (*list2)->x) {
return advance(list1);
}
return advance(list2);
}
main function:
ErrorCode mergeSortedLists(Node list1, Node list2, Node *merged_out) {
if (!merged_out) {
return NULL_ARGUMENT;
}
if (!list1 || !list2) {
return EMPTY_LIST;
}
if (!isListSorted(list1) || !isListSorted(list2)) {
return UNSORTED_LIST;
}
Node ptr = *merged_out;
int total_len = getListLength(list1) + getListLength(list2);
for (int i = 0; i < total_len; i++) {
int min = getMin(&list1, &list2);
if (i != 0) {
ptr->next = malloc(sizeof(*ptr));
if (!ptr->next) {
destroyList(*merged_out);
return MEMORY_ERROR;
}
ptr = ptr->next;
}
ptr->x = min;
}
ptr->next = NULL;
return SUCCESS;
}
This is the classical merge sort code where you have four cases provided that not both lists are exhausted:
a is exhausted;
b is exhausted;
a < b and
a ≥ b.
You have tried to coalesce the two first cases where one of the nodes is null with the comparison, but because your lists can have INT_MAX as value, that solution isn't robust.
Write out these cases explicitly. First a little auxiliary function that advances a node and returns the value:
static int advance(Node *nd)
{
int res = (*nd)->x;
*nd = (*nd)->next;
return res;
}
Now your actual function is very simple:
int getMin(Node *list1, Node *list2)
{
assert(*list1 || *list2);
if (*list1 == NULL) return advance(list2);
if (*list2 == NULL) return advance(list1);
if ((*list1)->x < (*list2)->x) return advance(list1);
return advance(list2);
}
See it in action on ideone.

Binary Tree deletion setting to NULL after freeing

I'm performing binary tree deletion in c.I was trying out few methods interestingly this weird situation came.
void Delete(){
struct BinaryTree* ptr = root;
int element;
printf("Enter element to delete : ");
scanf("%d",&element);
while(ptr){
if(element>ptr->data)
ptr = ptr->right;
else if(element<ptr->data)
ptr = ptr->left;
else
break;
}
if(ptr->left && ptr->right){
struct BinaryTree **smallest = &(ptr);
smallest = &((*smallest)->right);
while((*smallest)->left){
smallest = &((*smallest)->left);
}
ptr->data = (*smallest)->data;
free(*smallest);
*smallest = NULL;
} else if(ptr->left){
/*rest cases*/
}
}
The above code works and it sets the the NODE to NULL.
But when i do this procedure in this way it doesn't set to NULL.
if(ptr->left && ptr->right){
struct BinaryTree *smallest = ptr;
smallest = smallest->right;
while(smallest->left){
smallest = smallest->left;
}
ptr->data = smallest->data;
struct BinaryTree **refsmall = &smallest;
free(*refsmall);
*refsmall = NULL;
}
Aren't these two methods are same? If not can someone explain me how they are different?Why the first method work and second didn't?
You should avoid using global variables in your code. If you really want to use globals the first version of delete should look like this:
void Delete(){
/* at some point you will need to change the 'real' root, not the copy of it */
struct BinaryTree **ptr = &root;
int element;
printf("Enter element to delete : ");
scanf("%d",&element);
while(*ptr){
if(element > (*ptr)->data)
ptr = &(*ptr)->right;
else if(element < (*ptr)->data)
ptr = &(*ptr)->left;
else
break;
}
if((*ptr)->left && (*ptr)->right){
struct BinaryTree **smallest = ptr;
smallest = &(*smallest)->right;
while((*smallest)->left){
smallest = &(*smallest)->left;
}
(*ptr)->data = (*smallest)->data;
free(*smallest);
*smallest = NULL;
} else if((*ptr)->left){
/*rest cases*/
}
}
In the first version you would not be able to delete the root.
struct node {
struct node *l,*r;
int data;
};
void delnode(struct node **pp, int data)
{
struct node *del, *l,*r;
// Walk the tree
while(*pp) {
if ((*pp)->data < data) {pp = &(*pp)->l; continue;}
if ((*pp)->data > data) {pp = &(*pp)->r; continue;}
break; // found it!
}
if (!*pp) return; // not found
del = *pp;
l = del->l;
r = del->r;
// If only one child it wil take del's place.
if (!r) *pp = l;
else if (!l) *pp = r;
// del has two children.
// pick one (R) child, and append the (L) other onto its (Leftmost) shoulder
else {
*pp = r;
for (pp= &del->r; *pp; pp=&(*pp)->l) {;} // find Leftmost NULL pointer in the R tree
*pp = l;
}
free(del);
}

Free a binary tree without recursion

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.

Sequence insert at arbitrary index implemented with Linked list

I'm trying to implement sequence_insert_at using the add_to_front function here
Everything before
typedef struct sequence *Sequence;
is pasted from another c file.
void sequence_insert_at(Sequence s, int pos, int item)
{
struct node* temp = s->lst;
for(; pos > 0; --pos)
{
temp = temp->rest;
}
add_to_front(&temp, item);
++s->length;
if(!temp->rest)
{
s->end = temp;
}
//s->lst = temp;
}
I don't know why I keep getting a runtime error. if I clone s->lst and traverse the clone, I'm not modifying the pointer to the node in s, but if I change temp, s->lst should have the reflected changes since the nodes are all linked still. Any ideas as to how to fix this? I tried creating another node that is one before the temp after traversal, and then setting it->rest = temp, but that failed as well.
following mistakes a could spot but only so far to get the main function run
new_sequence does not initialize anything in Sequence it creates. lst is not initialized when you access it in sequence_insert_at
struct node* temp = s->lst;
here how it should look like
Sequence new_sequence()
{
Sequence s = malloc(sizeof(struct sequence));
if(!s)
{
printf("Out of memory. Can't allocate s\n");
exit(EXIT_FAILURE);
}
s->lst = malloc(sizeof(struct node));
if(! s->lst) {
printf("Out of memory. Can't allocate lst\n");
}
s->lst->rest = NULL;
s->length = 0;
return s;
}
also s->lst->rest has to be set to NULL, this is what tells that the list has no more elements an not end witch turns obsolete.
struct sequence
{
struct node* lst;
int length;
};
You should be passing the sequence itself to your functions not a pointer to some internal data in the sequence.
add_to_front(&temp, item);
Your sequence_insert_at function should be the one that can handle any position not add_to_front() so it is easier to call with the position 0 from add_to_front() and your having the the hole work done in one function, not a half here and a half there.
void sequence_insert_at(Sequence s, int pos, int item)
{
if(s && pos <= s->length) {
print_sequence(s);
struct node *newnode = malloc(sizeof(struct node));
if (newnode == NULL) {
printf("ERROR! add_to_front ran out of memory!\n");
exit(EXIT_FAILURE);
}
newnode->first = item;
struct node* temp = s->lst;
struct node* prv = NULL;
for(int i = 0; i < pos; i++) {
printf("skip %d\n", temp->first);
prv = temp;
temp = temp->rest;
}
newnode->rest = temp;
if(pos == 0) {
printf("insert as first\n");
s->lst = newnode;
} else {
printf("insert before %d\n", temp->first);
prv->rest = newnode;
}
++s->length;
}
}
and in add_to_front only one statement is needed
void add_to_front(Sequence s, int item) {
sequence_insert_at(s, 0, item);
}
as for inserting at the back of the list
void add_to_back(Sequence s, int item) {
sequence_insert_at(s, s->length, item);
}
A small test with the main function
void print_sequence(Sequence s)
{
struct node* temp = s->lst;
for(int i = 0; i < s->length; temp = temp->rest) {
printf("%d ", temp->first);
i++;
}
printf("\n");
}
int main()
{
Sequence derp = new_sequence();
sequence_insert_at(derp, 0, 14);
add_to_front(derp, 16);
sequence_insert_at(derp, 0, 17);
sequence_insert_at(derp, 2, 15);
add_to_back(derp, 13);
print_sequence(derp);
delete_sequence(derp);
return 0;
}
output is:
17 16 15 14 13
You'll have to go trough the other functions and fix them.
Finally i should note that variable names you have choosen are little bit confusing if not misleading, i would name them this way
typedef struct node {
int data; /* the data that a node holds */
struct node* next; /* the pointer to the next node */
} Node_t;
typedef struct sequence {
struct node* head; /* head or first element of the sequence/list */
int length; /* length is ok but size is better */
} Sequence_t;

Resources