Nonrecursive/Iterative Binary Search Tree in C (Homework) - c

How can I create/delete a node in a Binary Search Tree using Iterative Algorithm in C?

Iterative insertion:
struct tree_node *Insert_Element (struct tree_node *root, void *key, void *data) {
struct tree_node *new_node, *node;
node = root;
do {
switch (compare(key, node->key)) {
case -1: {
if (node->left == NULL) {
if ((new_node = create_node(key, data)) == NULL) {
return NULL;
}
node->left = new_node;
return new_node;
}
node = node->left;
} break;
case 1: {
if (node->right == NULL) {
if ((new_node = create_node(key, data)) == NULL) {
return NULL;
}
node->right = new_node;
return new_node;
}
node = node->right;
} break;
default: {
return node;
}
}
} while (node != NULL);
return NULL;
}

Iterative insertion & deletion in BST
struct bst {
int data;
struct bst *left;
struct bst *right;
};
typedef struct bst bst_t;
bst_t *get_new_node(int val)
{
bst_t *node = (bst_t *) malloc(sizeof(bst_t));
node->data = val;
node->left = NULL;
node->right= NULL;
return node;
}
bst_t *insert(bst_t *root, int val)
{
if(!root) return get_new_node(val);
bst_t *prev = NULL, *ptr = root;
char type = ' ';
while(ptr) {
prev = ptr;
if(val < ptr->data) {
ptr = ptr->left;
type = 'l';
} else {
ptr = ptr->right;
type = 'r';
}
}
if(type == 'l')
prev->left = get_new_node(val);
else
prev->right = get_new_node(val);
return root;
}
int find_minimum_value(bst_t *ptr)
{
int min = ptr ? ptr->data : 0;
while(ptr) {
if(ptr->data < min) min = ptr->data;
if(ptr->left) {
ptr = ptr->left;
} else if(ptr->right) {
ptr = ptr->right;
} else ptr = NULL;
}
return min;
}
bst_t *delete(bst_t *root, int val)
{
bst_t *prev = NULL, *ptr = root;
char type = ' ';
while(ptr) {
if(ptr->data == val) {
if(!ptr->left && !ptr->right) { // node to be removed has no children's
if(ptr != root && prev) { // delete leaf node
if(type == 'l')
prev->left = NULL;
else
prev->right = NULL;
} else root = NULL; // deleted node is root
} else if (ptr->left && ptr->right) { // node to be removed has two children's
ptr->data = find_minimum_value(ptr->right); // find minimum value from right subtree
val = ptr->data;
prev = ptr;
ptr = ptr->right; // continue from right subtree delete min node
type = 'r';
continue;
} else { // node to be removed has one children
if(ptr == root) { // root with one child
root = root->left ? root->left : root->right;
} else { // subtree with one child
if(type == 'l')
prev->left = ptr->left ? ptr->left : ptr->right;
else
prev->right = ptr->left ? ptr->left : ptr->right;
}
}
free(ptr);
}
prev = ptr;
if(val < ptr->data) {
ptr = ptr->left;
type = 'l';
} else {
ptr = ptr->right;
type = 'r';
}
}
return root;
}

Nice post. Just a suggestion. I believe, finding a minimum value in a BST doesn't have to traverse the right subtree. Minimum value must be either on the left subtree or node itself(in case if left subtree is null). Function find_minimum_value can be optimized if right subtree traversal is removed.
int find_minimum_value(bst_t *ptr)
{
while(ptr->left) {
ptr = ptr->left;
}
return ptr->data;
}

In C, you can cast the pointers in the tree to intptr_t type and perform bitwise operations to them.
As you traverse down the tree, you can store the 'parent' pointer of a node by xoring it with the pointer you traversed with. You can then traverse back up the tree by xoring the the address of the node you are coming from with the modified pointer.
A worked example of this traditional technique is at http://sites.google.com/site/debforit/efficient-binary-tree-traversal-with-two-pointers
Given the ability to traverse the tree without recursion, you can then create iterative versions of any of the algorithms based on traversing the tree.

Related

Stuck at deleting node from Binary Search Tree

I have been trying to follow the textbook "Introduction to Algorithms" but I'm stuck at the following step when deleting a node from a BST - when the node to be deleted has both children
My code is below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bst.h"
void error()
{
fprintf(stderr, "%s\n", "Error assigning memory to node");
exit(1);
}
void insert(node **root, int key)
{
node *t1, *t2;
if (*root == NULL) {
printf("Root is null\n");
*root = (node *)malloc(sizeof(node));
if (*root==NULL) {
fprintf(stderr, "%s\n", "Cannot allocate memory for node in Insert");
exit(1);
}
(*root)->key = key;
(*root)->left = (*root)->right = NULL;
}
else {
printf("Root contains data. Inserting new node.\n");
t1 = *root;
while (t1 != NULL) {
t2 = t1;
if (key < t1->key)
t1 = t1->left;
else
t1 = t1->right;
}
if(key < t2->key) {
t2->left = (node *) malloc(sizeof(node));
t2 = t2->left;
if (t2==NULL)
error();
t2 -> key = key;
}
else {
t2->right = (node *) malloc(sizeof(node));
t2 = t2->right;
if (t2==NULL)
error();
t2->key = key;
}
}
}
void inorder(node * root)
{
if (root!=NULL) {
inorder(root->left);
printf("%d ->", root->key);
inorder(root->right);
}
}
node * search(node *root, int key)
{
node * t = root;
while (t!=NULL)
{
if (key == t->key)
return t;
else if (key < t->key)
t = t->left;
else
t = t->right;
}
return NULL;
}
node * getparent(node * root, int key)
{
node * t = root, *parent = NULL;
while (t!=NULL)
{
if (key == t->key)
return parent;
else if (key < t->key)
t = t->left;
else
t = t->right;
parent = t;
}
return NULL;
}
node * delete(node *root, int key)
{
node * todelete = search(root,key), *parent = getparent(root, key), *y;
if (todelete==NULL) {
fprintf(stderr, "%s\n", "Key not found");
exit(2);
}
if (todelete->left == NULL && todelete->right==NULL) { //Deleting node with no children
if (todelete == parent->left)
parent->left = NULL;
else
parent->right = NULL;
free(todelete);
return root;
}
else if (todelete->left && !todelete->right) {
if (todelete == parent->left)
parent->left = todelete->left;
else
parent->right = todelete->right;
free(todelete);
return root;
}
else if (todelete->right & !todelete->left) {
if (todelete == parent->left)
parent->left = todelete->left;
else
parent->right = todelete->right;
free(todelete);
return root;
}
else
{
node * yparent = NULL;
y= todelete->right;
while (y->left!=NULL)
{
y = y->left;
yparent = y;
}
if(yparent != todelete) {
//stuck here
}
}
}
bst.h:
struct treenode
{
int key;
struct treenode *left;
struct treenode *right;
};
typedef struct treenode node;
node * getparent(node * root, int key);
void insert(node **root, int key);
node * search(node *root, int key);
node * delete(node *root, int key);
void inorder(node * root);
Any guidance would be much appreciated. I should be trying to set the y = y->right and then set todelete->right = y correct?
I'm stuck at the following step when deleting a node from a BST - when the node to be deleted has both children
It follows from the properties of a BST that if a node N has two children then every node in the subtree rooted at the left child is less than every node in the subtree rooted at the right child and vise versa. In particular, the largest node in the left subtree, Lmax, is less than all the nodes in the right subtree, and the least node in the right subtree, Rmin, is larger than all the nodes of the left subtree. These are the nodes immediately preceding and following N in an in-order traversal. Both of those descendants are easy to find, and neither has more than one child (else they could neither be max nor min in any subtree).
It follows, then, that if you want to delete node N then you may choose either Lmax or Rmin, delete it from the tree (which is easy because it has at most one child), and replace N with it. Alternatively, delete Lmax or Rmin, and replace the key of node N with the key of that deleted node.
Changed the code to the following and it works (for the delete functions):
static void transplant(node * root, node * u, node * v)
{
node *uparent = getparent(root, u->key);
node * vparent = getparent(root, v->key);
if (uparent == NULL)
root = v;
else if (u == uparent->left)
uparent->left = v;
else uparent->right = v;
if (v!=NULL)
vparent = uparent;
}
node * delete(node *root, int key)
{
node * todelete = search(root,key), *parent = getparent(root, key), *y;
if (todelete==NULL) {
fprintf(stderr, "%s\n", "Key not found");
exit(2);
}
if (todelete->left == NULL && todelete->right==NULL) { //Deleting node with no children
if (todelete == parent->left)
parent->left = NULL;
else
parent->right = NULL;
free(todelete);
return root;
}
else if (todelete->left && !todelete->right) {
if (todelete == parent->left)
parent->left = todelete->left;
else
parent->right = todelete->left;
free(todelete);
return root;
}
else if (todelete->right && !todelete->left) {
if (todelete == parent->left)
parent->left = todelete->right;
else
parent->right = todelete->right;
free(todelete);
return root;
}
else {
y = todelete->right;
while(y->left!=NULL)
{
y = y->left;
}
node *yparent = getparent(root, y->key);
if (yparent != todelete)
{
transplant(root, y, y->right);
y->right = todelete->right;
node * yrightparent = getparent(root, y->right->key);
yrightparent = y;
}
transplant(root, todelete, y);
y->left = todelete->left;
node *yleftparent = getparent(root, y->left->key);
yleftparent = y;
free(todelete);
return root;
}

Deletion of node in Binary Search Tree is throwing error

Experts, this is my code of creation and deletion of nodes in Binary Search Tree. It's working fine for insertion, but throwing segmentation fault (core dumped) when trying to delete a node (on invoking deleteNode( ) function). I don't understand what's actually the problem. Please help! Thank you in advance!
#include <stdio.h>
#include <stdlib.h>
int size = 0;
typedef struct mylist{
int data;
struct mylist *left;
struct mylist *right;
}node;
node *root;
void create_root(node *root){
root = NULL;
}
//Inserting nodes
node* insert(node *root, int val){
node *ptr, *parentptr, *nodeptr;
ptr = (node*)malloc(sizeof(node));
ptr -> data = val;
ptr -> left = NULL;
ptr -> right = NULL;
if(root == NULL)
root = ptr;
else{
parentptr = NULL;
nodeptr = root;
while(nodeptr != NULL){
parentptr=nodeptr;
if(val < nodeptr -> data)
nodeptr = nodeptr -> left;
else
nodeptr = nodeptr -> right;
}
if(val < parentptr -> data)
parentptr -> left = ptr;
else
parentptr -> right = ptr;
}
return root;
}
node* minValueNode(node* root)
{
node* cur = root;
while (cur->left != NULL)
cur = cur->left;
return cur;
}
node* deleteNode(node* root, int key)
{
if (root == NULL){
printf("\nValue not found\n");
}
if (key < root-> data)
root->left = deleteNode(root->left, key);
else if (key > root-> data)
root->right = deleteNode(root->right, key);
else
{
if (root->left == NULL)
{
node *temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL)
{
node *temp = root->left;
free(root);
return temp;
}
node* temp = minValueNode(root->right); //Inorder successor
root->data = temp->data;
root->right = deleteNode(root->right, temp->data);
}
return root;
}
void main(){
int option, val;
node *ptr;
int flag = 1;
create_root(root);
while(flag != 2){
printf("\nChoose-\n1-Insert\n2-Delete\n3-Exit\n");
scanf("%d", &option);
switch(option){
case 1:{
printf("\nEnter the value of new node\n");
size++;
scanf("%d", &val);
root = insert(root, val);
break;
}
case 2:{
int k;
printf("Enter the value to delete");
scanf("%d",&k);
root=deleteNode(root, k);
size--;
break;
}
case 3:
flag=2;
break;
default:
printf("\nWrong entry\n");
}
}
}
You must either return NULL in the first if() in deleteNode(), or you must put an else before the second if()
node* deleteNode(node* root, int key)
{
if (root == NULL){
printf("\nValue not found\n");
return NULL; // <== This was missing.
}
...
}
or alternatively (perhaps intended?):
node* deleteNode(node* root, int key)
{
if (root == NULL){
printf("\nValue not found\n");
}
else if(key < root->data)
...
}
At the moment this falls through to the next if(key < root->data) even when root is null, which causes the segfault.
Also: Use nullptr if you can use C++11.

Add function in a trie structure does not work properly

I'm trying to write a function to add words in a trie, and count the number of times it has been added. But it always returns 1.
Can anybody help me?
struct node
{
struct node* next;
struct node* child;
char data;
int value;
};
typedef struct node Node;
Node* getNode(char data)
{
Node* newptr;
newptr = calloc(1,sizeof(Node));
newptr->next = NULL;
newptr -> child = NULL;
newptr->data = data;
newptr -> value = 0;
return newptr;
}
Node* add(Node* parent,char* str)
{
Node* current;
current = parent->child;
while (current != NULL && current->data != str[0])
{
current = current->next;
}
if (current == NULL)
{
current = getNode(str[0]);
if (str[0] == 0)
{
current->value = 1;
return current;
}
return add(current,str + 1);
}
if (str[0] == 0)
{
(current->value)++;
return current;
}
return add(current,str+1);
}
cm: getNode() and Node definitions added!

C malloc to pointer to NULL not working

I am writing a function that inserts a new node in a binary search tree. In order to avoid having too many if-else's, I am using a pointer called nodeSide that points to either node's left or right, as follows:
void insertHelper(Node *node, int val) {
Node *nodeSide;
if (val < node->val) {
nodeSide = node->left;
} else {
nodeSide = node->right;
}
if (nodeSide == NULL) {
nodeSide = (Node *)malloc(sizeof(Node));
nodeSide->val = val;
nodeSide->left = NULL;
nodeSide->right = NULL;
return;
}
else {
insertHelper(nodeSide, val);
}
}
The node however, isn't actually being added. It seems like doing this:
Node *node = malloc(...);
node->left = NULL;
Node *anotherNode = nodeLeft;
anotherNode = malloc(...);
doesn't in fact add a new node to tree. Any ideas why? The pointer should be pointing to the right place, regardless whether it is null or not. Or am I wrong here?
Here is my full code:
#include <stdlib.h>
#include <stdio.h>
typedef struct _node {
int val;
struct _node * left;
struct _node * right;
int ht;
} Node;
void insertHelper(Node *node, int val) {
Node *nodeSide;
if (val < node->val) {
nodeSide = node->left;
} else {
nodeSide = node->right;
}
if (nodeSide == NULL) {
nodeSide = (Node *)malloc(sizeof(Node));
nodeSide->val = val;
nodeSide->left = NULL;
nodeSide->right = NULL;
return;
}
else {
insertHelper(nodeSide, val);
}
}
Node * getNode(int value) {
Node * node = (Node * )malloc(sizeof(Node));
node->val = value;
node->left = NULL;
node->right = NULL;
node->ht = 0;
return node;
}
Node * getTree() {
Node *root = getNode(3);
Node *rootLeft = getNode(2);
root->left = rootLeft;
Node *rootRight = getNode(4);
root->right = rootRight;
Node *rootRightRight = getNode(5);
rootRight->right = rootRightRight;
return root;
}
int main() {
Node * root = getTree();
insertHelper(root, 6);
// to verify:
printf("%d", root->right->right->right->val);
return 0;
}
Your code does not store the new node that you create anywhere in your tree.
Perhaps you could do e.g.
if (nodeSide == NULL) {
nodeSide = (Node *)malloc(sizeof(Node));
nodeSide->val = val;
nodeSide->left = NULL;
nodeSide->right = NULL;
if (val < node->val)
node->left = nodeSide;
} else {
node->right = nodeSide;
}
return;
}
But you could use a double pointer, to avoid the extra if/else there:
Node **nodeSide;
if (val < node->val) {
nodeSide = &node->left;
} else {
nodeSide = &node->right;
}
if (*nodeSide == NULL) {
*nodeSide = (Node *)malloc(sizeof(Node));
(*nodeSide)->val = val;
(*nodeSide)->left = NULL;
(*nodeSide)->right = NULL;
return;
}
else {
insertHelper(*nodeSide, val);
}
}
Youre insertHelper seems to lack one relevant line of code just before the return:
node->left = nodeSide;
But keep in mind which side to add the value. Maybe you should track the relevant side as variable inside the function.

Delete function in Binary Tree in C

I'm writing the basic functions for binary tree and everything seems to compile and run, but when i try to use my delete function it doesn't do anything.
After executing i get the same sequence of numbers, so i'm trying to figure out what's wrong with the Delete function, is it logically correct?
#include <stdio.h>
#include <stdlib.h>
typedef struct treeNode
{
int data;
struct treeNode *left;
struct treeNode *right;
}treeNode;
treeNode *Insert(treeNode *node, int data)
{
if(node == NULL)
{
treeNode *temp;
temp = malloc(sizeof(treeNode));
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
if(data > (node->data))
{
node->right = Insert(node->right, data);
}
else if(data < (node->data))
{
node->left = Insert(node->left, data);
}
return node;
}
treeNode *Delete(treeNode *node, int data)
{
if(node == NULL)
{
printf("element not found\n");
}
else if(data < node->data)
{
node->left = Delete(node->left, data);
}
else if(data > node->data)
{
node->right = Delete(node->right, data);
}
return node;
}
treeNode *Find(treeNode *node, int data)
{
if(node == NULL)
{
return NULL;
}
if(data > node->data)
{
return Find(node->right, data);
}
else if(data < node->data)
{
return Find(node->left, data);
}
else
{
return node;
}
}
void Print(treeNode *node)
{
if(node == NULL)
{
return;
}
Print(node->left);
printf("%d", node->data);
Print(node->right);
}
int main()
{
treeNode *root = NULL;
root = Insert(root, 5);
root = Insert(root, 8);
root = Insert(root, 6);
root = Insert(root, 4);
root = Insert(root, 3);
root = Insert(root, 9);
root = Insert(root, 10);
root = Insert(root, 19);
Print(root);
printf("\n");
root = Delete(root, 5);
root = Delete(root, 8);
Print(root);
printf("\n");
treeNode *temp;
temp = Find(root, 8);
if(temp == NULL)
{
printf("Element 8 not found\n");
}
else
{
printf("Element 8 found\n");
}
temp = Find(root, 5);
if(temp == NULL)
{
printf("element 5 not found\n");
}
else
{
printf("element 5 found\n");
}
}
Basically i was only replacing the node with itself, but this can be solved by replacing the deleted node with the minimum element in the right subtree or the maximum element in the left subtree.
The function that works:
treeNode * Delete(treeNode *node, int data)
{
treeNode *temp;
if(node==NULL)
{
printf("Element Not Found");
}
else if(data < node->data)
{
node->left = Delete(node->left, data);
}
else if(data > node->data)
{
node->right = Delete(node->right, data);
}
else
{
/* Now We can delete this node and replace with either minimum element
in the right sub tree or maximum element in the left subtree*/
if(node->right && node->left)
{
/* Here we will replace with minimum element in the right sub tree */
temp = FindMin(node->right);
node -> data = temp->data;
/* As we replaced it with some other node, we have to delete that node */
node -> right = Delete(node->right,temp->data);
}
else
{
/* If there is only one or zero children then we can directly
remove it from the tree and connect its parent to its child */
temp = node;
if(node->left == NULL)
node = node->right;
else if(node->right == NULL)
node = node->left;
free(temp); /* temp is longer required */
}
}
return node;
}

Resources