Find a node in a binary search tree - c

My findNode is called in my insert function with the address of tree. Since im inserting the first word tree should be NULL but when I debug it skips over this check in my FindWords function.
Im not sure exactly what is the value of tree here if it is not NULL, please advise.
struct TREENODE {
struct TREENODE *parent; // point to parent node of this node
struct TREENODE *left; // point to left child of this node
struct TREENODE *right; // point to right child of this node
char *word; // store a unique word in the text file
int count; // num of times this word appears in the file
};
typedef struct TREENODE NODE;
#define MAXWORDLEN 1000
when I insert the first word, tree should be NULL here because no words exist. But instead of this function returning NULL when no words exists its skips to the if statement (strcmp(word, tree->word == 0)) and causes a segmentation fault.
NODE* findNode(char *word, NODE* tree) {
// return node storing word if exists
if (tree == NULL){return NULL;}
if (strcmp(word, tree->word)==0)
return tree;
if (strcmp(word, tree->word) <0)
return findNode(word, tree->left);
return findNode(word, tree->right);
}
void insertNode(char *word, NODE** address_of_tree ) {
NODE *tree = *address_of_tree;
NODE *node;
node = findNode(word, tree);
if (node == NULL) {
NODE *new_node = malloc(sizeof(NODE));
new_node->word = word;
new_node->parent = *address_of_tree;
new_node->left = NULL;
new_node->right = NULL;
if (tree == NULL) {
*address_of_tree = new_node;
return;
}
if (strcmp(word, tree->word) < 0) {
// word must be added to left subtree
if (tree->left !=NULL) insertNode(word, &tree->left);
else {
new_node->parent = tree;
tree->left = new_node;
}
}
else {
if (tree->right != NULL) insertNode(word, &(tree->right));
else {
new_node->parent = tree;
tree->right = new_node;
}
}
}
else {
// update the count for the word
node->count += 1;
}
}
void printTree(NODE* tree) {
// print each word and its count in alphabetical order
if (tree == NULL) return;
printTree(tree->left);
printf("word: %s\ncount: %d", tree->word, tree->count);
printTree(tree->right);
}
int main() {
// read text from stdin
// each time we read a word
// insert this word into the tree
NODE *tree; // the tree we are using to store the words
char word[MAXWORDLEN];
while(scanf("%s", word) != EOF) {
// insert this word into the tree
insertNode(word, &tree);
}
printTree(tree);
return 0;
}

You are taking input in buffer word and passing it to insertNode(). In the insertNode(), you are doing
new_node->word = word;
which will make all the new node new_node->word pointer point to same buffer word. Any changes in the content of word buffer will reflect in all the nodes nodes->word value. Instead, you should do
new_node->word = strdup(word);
strdup() duplicates the given string. It uses malloc to obtain memory for the new string. Make sure to free it once you are done with it.
You should also initialise the tree with NULL before creating tree
NODE *tree = NULL;
because you are passing tree pointer to insertNode() and in the insertNode() you are checking for tree pointer is NULL or not. So, you should explicitly initialise the tree pointer with NULL.

Related

Removing unique elements in a doubly linked list in C

I need a little help removing unique characters in a doubly linked list in C. So here's the logic I tried implementing: I counted the occurrence of each character in the doubly linked list. If it's occurrence is 1 time, then it is unique element and needs to be deleted. I'll be repeating the process for all elements. But my code in remove_unique_dll() function isn't working properly, please help me fix it. Here's my code-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
int len;
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
newNode->data = data;
if (head == NULL)
{ //If dll is empty
head = tail = newNode; //Both head and tail will point to newNode
head->prev = NULL; //head's previous will point to NULL
tail->next = NULL; //tail's next will point to NULL, as it is the last node of the list
}
else
{
tail->next = newNode; //newNode will be added after tail such that tail's next points to newNode
newNode->prev = tail; //newNode's previous will point to tail
tail = newNode; //newNode will become new tail
tail->next = NULL; //As it is last node, tail's next will point to NULL
}
}
void remove_unique_dll()
{
struct node *current = head;
struct node *next;
struct node *prev;
int cnt;
while (current != NULL)
{
next = current->next;
cnt = 1;
//printf("!%c ",next->data);
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if (cnt == 1)
{
prev = current->prev;
//printf("#%c %d",prev->data,cnt);
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
if (next == NULL)
{
tail = prev;
}
else
{
next->prev = prev;
}
}
current = current->next;
//printf("#%c ",current->data);
}
head = current;
}
void display()
{
struct node *current = head; //head the global one
while (current != NULL)
{
printf("%c<->", current->data); //Prints each node by incrementing pointer.
current = current->next;
}
printf("NULL\n");
}
int main()
{
char s[100];
int i;
printf("Enter string: ");
scanf("%s", s);
len = strlen(s);
for (i = 0; i < len; i++)
{
addNode(s[i]);
}
printf("Doubly linked list: \n");
display();
remove_unique_dll();
printf("Doubly linked list after removing unique elements: \n");
display();
return 0;
}
The output is like this-
If you uncomment the printf() statements inside remove_unique_dll() you'll notice that no code below inner while loop is being executed after inner while loop ends. What's the issue here and what's the solution?
Sample input- aacb
Expected output- a<->a<->NULL
Some issues:
You shouldn't assign head = current at the end, because by then current is NULL
The next you use in the deletion part is not the successor of current, so this will make wrong links
As you progress through the list, every value is going to be regarded as unique at some point: when it is the last occurrence, you'll not find a duplicate anymore, as your logic only looks ahead, not backwards.
When you remove a node, you should free its memory.
Not a big issue, but there is no reason to really count the number of duplicates. Once you find the first duplicate, there is no reason to look for another.
You should really isolate the different steps of the algorithm in separate functions, so you can debug and test each of those features separately and also better understand your code.
Also, to check for duplicates, you might want to use the following fact: if the first occurrence of a value in a list is the same node as the last occurrence of that value, then you know it is unique. As your list is doubly linked, you can use a backwards traversal to find the last occurrence (and a forward traversal to find the first occurrence).
Here is some suggested code:
struct node* findFirstNode(char data) {
struct node *current = head;
while (current != NULL && current->data != data) {
current = current->next;
}
return current;
}
struct node* findLastNode(char data) {
struct node *current = tail;
while (current != NULL && current->data != data) {
current = current->prev;
}
return current;
}
void removeNode(struct node *current) {
if (current->prev == NULL) {
head = current->next;
} else {
current->prev->next = current->next;
}
if (current->next == NULL) {
tail = current->prev;
} else {
current->next->prev = current->prev;
}
free(current);
}
void remove_unique_dll() {
struct node *current = head;
struct node *next;
while (current != NULL)
{
next = current->next;
if (findFirstNode(current->data) == findLastNode(current->data)) {
removeNode(current);
}
current = next;
}
}
You have at least three errors.
After counting the number of occurrences of an item, you use next in several places. However, next has been used to iterate through the list. It was moved to the end and is now a null pointer. You can either reset it with next = current->next; or you can change the places that use next to current->next.
At the end of remove_unique_dll, you have head=current;. There is no reason to update head at this point. Whenever the first node was removed from the list, earlier code in remove_unique_dll updated head. So it is already updated. Delete the line head=current;.
That will leave code that deletes all but one occurrence of each item. However, based on your sample output, you want to leave multiple occurrences of items for which there are multiple occurrences. For that, you need to rethink your logic in remove_unique_dll about deciding which nodes to delete. When it sees the first a, it scans the remainder of the list and sees the second, so it does not delete the first a. When it sees the second a, it scans the remainder of the list and does not see a duplicate, so it deletes the second a. You need to change that.
Let's consider your code step by step.
It seems you think that in this declaration
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
the both pointers head and tail are explicitly initialized by NULL. Actually only the pointer tail is explicitly initialized by NULL. The pointer head is initialized implicitly as a null pointer only due to placing the declaration in file scope. It to place such a declaration in a block scope then the pointer head will be uninitialized.
Instead you should write
struct node *head = NULL, *tail = NULL; //Represent the head and tail of the doubly linked list
Also it is a very bad approach when the functions depend on these global variables. In this case you will be unable to have more than one list in a program.
Also the declaration of the variable len that is used only in main as a global variable
int len;
also a bad idea. And moreover this declaration is redundant.
You need to define one more structure that will contain pointers head and tail as data members as for example
struct list
{
struct node *head;
struct node *tail;
};
The function addNode can invoke undefined behavior when a new node can not be allocated
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
//...
You should check whether a node is allocated successfully and only in this case change its data members. And you should report the caller whether a node is created or not.
So the function should return an integer that will report an success or failure.
In the function remove_unique_dll after this while loop
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if cnt is equal to 1
if (cnt == 1)
//..
then the pointer next is equal to NULL. And using the pointer next after that like
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
is wrong.
Also you need to check whether there is a preceding node with the same value as the value of the current node. Otherwise you can remove a node that is not a unique because after it there are no nodes with the same value.
And this statement
head = current;
does not make sense because after the outer while loop
while (current != NULL)
the pointer current is equal to NULL.
Pay attention that the function will be more useful for users if it will return the number of removed unique elements.
Here is a demonstration program that shows how the list and the function remove_unique_dll can be defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct list
{
struct node *head;
struct node *tail;
};
int addNode( struct list *list, char data )
{
struct node *node = malloc( sizeof( *node ) );
int success = node != NULL;
if (success)
{
node->data = data;
node->next = NULL;
node->prev = list->tail;
if (list->head == NULL)
{
list->head = node;
}
else
{
list->tail->next = node;
}
list->tail = node;
}
return success;
}
size_t remove_unique_dll( struct list *list )
{
size_t removed = 0;
for ( struct node *current = list->head; current != NULL; )
{
struct node *prev = current->prev;
while (prev != NULL && prev->data != current->data)
{
prev = prev->prev;
}
if (prev == NULL)
{
// there is no preceding node with the same value
// so the current node is possibly unique
struct node *next = current->next;
while (next != NULL && next->data != current->data)
{
next = next->next;
}
if (next == NULL)
{
// the current node is indeed unique
struct node *to_delete = current;
if (current->prev != NULL)
{
current->prev->next = current->next;
}
else
{
list->head = current->next;
}
if (current->next != NULL)
{
current->next->prev = current->prev;
}
else
{
list->tail = current->prev;
}
current = current->next;
free( to_delete );
++removed;
}
else
{
current = current->next;
}
}
else
{
current = current->next;
}
}
return removed;
}
void display( const struct list *list )
{
for (const node *current = list->head; current != NULL; current = current->next)
{
printf( "%c<->", current->data );
}
puts( "null" );
}
int main()
{
struct list list = { .head = NULL, .tail = NULL };
const char *s = "aabc";
for (const char *p = s; *p != '\0'; ++p)
{
addNode( &list, *p );
}
printf( "Doubly linked list:\n" );
display( &list );
size_t removed = remove_unique_dll( &list );
printf( "There are removed %zu unique value(s) in the list.\n", removed );
printf( "Doubly linked list after removing unique elements:\n" );
display( &list );
}
The program output is
Doubly linked list:
a<->a<->b<->c<->null
There are removed 2 unique value(s) in the list.
Doubly linked list after removing unique elements:
a<->a<->null
You will need at least to write one more function that will free all the allocated memory when the list will not be required any more.

C tree, delete an element if a condition is met

i have implemented a tree in C:
struct node
{
char *key;
struct node *left, *right;
};
// A utility function to create a new BST node
struct node *newNode(char *item)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}
// A utility function to do inorder traversal of BST
void inorder(struct node *root)
{
if (root != NULL)
{
inorder(root->left);
printf("%s\n", root->key);
inorder(root->right);
}
}
/* A utility function to
insert a new node with given key in
* BST */
struct node *insert(struct node *node, char *key)
{
/* If the tree is empty, return a new node */
if (node == NULL)
return newNode(key);
/* Otherwise, recur down the tree */
if (strcmp(key, node->key) < 0)
node->left = insert(node->left, key);
else
node->right = insert(node->right, key);
/* return the (unchanged) node pointer */
return node;
}
/* Given a non-empty binary search
tree, return the node
with minimum key value found in
that tree. Note that the
entire tree does not need to be searched. */
struct node *minValueNode(struct node *node)
{
struct node *current = node;
/* loop down to find the leftmost leaf */
while (current && current->left != NULL)
current = current->left;
return current;
}
/* Given a binary search tree
and a key, this function
deletes the key and
returns the new root */
struct node *deleteNode(struct node *root, char *key)
{
// base case
if (root == NULL)
return root;
// If the key to be deleted
// is smaller than the root's
// key, then it lies in left subtree
if (strcmp(key, root->key) < 0)
root->left = deleteNode(root->left, key);
// If the key to be deleted
// is greater than the root's
// key, then it lies in right subtree
else if (strcmp(key, root->key) > 0)
root->right = deleteNode(root->right, key);
// if key is same as root's key,
// then This is the node
// to be deleted
else
{
// node with only one child or no child
if (root->left == NULL)
{
struct node *temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL)
{
struct node *temp = root->left;
free(root);
return temp;
}
// node with two children:
// Get the inorder successor
// (smallest in the right subtree)
struct node *temp = minValueNode(root->right);
// Copy the inorder
// successor's content to this node
root->key = temp->key;
// Delete the inorder successor
root->right = deleteNode(root->right, temp->key);
}
return root;
}
I have defined a function that takes the Tree as input and deletes a node from it if a condition is met:
void applyFilter(struct node *Tree)
{
if (Tree != NULL)
{
applyFilter(Tree->left);
applyFilter(Tree->right);
for (short i = 0; i < MAX_CONSTRAINTS; i++)
{
if (strchr(Tree->key, constraints[i].letter) != NULL)
{
// delete the word from the tree
Tree = deleteNode(Tree, Tree->key);
break;
}
}
}
}
But i got segmentation fault.
The main goal is to make it work, with as little memory as possible (running).
I think I understand the problem, and it is caused by recursion, because if I delete a node it will give me an empty tree.
If you can give me an example, even a different one i will be really gratefull, because i worked on it a lot, but i am totally stucked.
Thank you!
It happens in minValueNode() after the call of the deleteNode(), because result that the Tree is empty
It happens in minValueNode() after the call of the deleteNode(), because result that the Tree is empty
Basically you already understand what the problem is. You will need to check whether the tree is empty and default the value to something inside minValueNode before you start looping. Because the loop assumes that you have something and if you happen to have nothing, then it's a faulty assumption and causes segfault.

No output on binary tree traversal in C

I am a rookie programmer and I have a project which implies using binary trees. All I have to do is to insert a node, delete a node and add two methods of tree traversal. The issue is I can't get my code to work. I decided to add few helper functions such as check_element and create_NewNode to help me out implement easier. I don't get an output on my console after running or it simply greets me with a runtime error. I have got a header file, IO.c file to store my functions and the main.c.to test header file Implemented functions.
Here is IO.c , used to store the functions.
#include <stdio.h>
#include <stdlib.h>
#include "Library.h"
struct node{
int data;
struct node *left;
struct node *right;
};
struct node *root;
/*-----------------------------------------------------------------------------------------*/
//function to determine if an element is already in the tree
void check_element( struct node *node, int value)
{
while( node != NULL ){
//checking if the value is here
if( value == node->data ){
printf("The element %d already exists in the tree!",value);
exit(0);
//if the value is smaller, go left
}else if( value < node->data ){
check_element( node->left, value );
//else go right
}else if( value > node->data ){
check_element( node->right, value );
//else the element was not found and we can add it to th tree
}else{
printf("Adding the element %d to the tree.",value);
exit(0);
}
}//end while
}//end check_element
/*-----------------------------------------------------------------------------------------*/
//helper function to crate a new node and set left and right pointers to NULL
struct node *create_NewNode( int value )
{
struct node *ptr;
struct node *temp = (struct node*)malloc(sizeof(struct node));
ptr = (struct node*)malloc(sizeof(struct node));
if( ptr == NULL){
printf("Memory allocation error!");
exit(-1);
}
//assigning the data to the newly created node
temp->data = value;
//setting left and right pointers to NULL
temp->left = NULL;
temp->right = NULL;
return temp;
}
/*-----------------------------------------------------------------------------------------*/
//function to add a new value to the tree;
struct node *insert_value( struct node *node, int new_value )
{
//checking if the element already exists to the tree
check_element( node, new_value );
//checking if the tree is empty
if( node == NULL ){
node = create_NewNode( new_value );
//if the value is smaller, we add it to the left
}else if( new_value < node->data ){
insert_value( node->left, new_value );
//else we add it to the right
}else{
insert_value( node->right, new_value );
}
return node;
}
/*-----------------------------------------------------------------------------------------*/
void printPostorder( struct node *node )
{
if (node == NULL){
printf("The tree is empty!");
exit(0);
}else{
//first go left
printPostorder( node->left );
//then go right
printPostorder( node->right );
//finally, print the node value
printf("%d", node->data);
}
}
/*-----------------------------------------------------------------------------------------*/
void inorder_traversal( struct node *node )
{
if( node == NULL) {
printf("The tree is empty!");
exit(0);
}else{
//first go left
inorder_traversal( node->left );
//print the node value
printf("%d ",node->data);
//then go right
inorder_traversal( node->right );
}
}
/*-----------------------------------------------------------------------------------------*/
This is the header file, called Library.h
//prototype for NewNode
struct node *create_NewNode( int value );
//prototype for insert_value
struct node *insert_value( struct node *node, int new_value );
//prototype for printPostordre
void printPostorder( struct node* node);
//prototype for printInorder
void inorder_traversal( struct node *node );
//prototype for check_element
void check_element( struct node *node, int value);
And, finally, the main.c: `enter code here:
#include <stdio.h>
#include <stdlib.h>
#include "Library.h"
int main()
{
// TEST CODE
struct node *root;
root = NULL;
insert_value(root, 1);
insert_value(root, 2);
insert_value(root, 3);
printPostorder( root );
inorder_traversal( root );
return 0;
}
PS: I did my best to write this code, but, as I said, I am a rookie and I'm pretty bad at coding.I'd also like to appologize for any grammar mistakes, i am not an englishman.
There may be more mistakes, but I read the create_node() and want to advice on it:
struct node *create_NewNode( int value )
{
struct node *ptr;
struct node *temp = malloc(sizeof(struct node));
ptr = malloc(sizeof(struct node));
if( ptr == NULL){
printf("Memory allocation error!");
exit(-1);
}
//assigning the data to the newly created node
temp->data = value;
//setting left and right pointers to NULL
temp->left = NULL;
temp->right = NULL;
return temp;
}
Here you are creating two nodes, while you intend to create only one. You treat temp as the new one, while you forget about ptr. You don't need to create another node!
What you need is the pointer of the tree, so that you add the newly constructed node at that tree (thus you could pass another parameter to that function, tree's pointer).
BTW, I removed the casts of malloc, as explained in Do I cast the result of malloc?
I suggest trying to fix your code after my advice. However, I will link you to treemanagement.c, which is c code for a tree, fully commented, and it's the way I learned about this data structure, it might can in handy in the future!
I forgot about this post. I have got it to work. This is what I used:
For the header file:
///\file Header.h
///\brief The header containing all the prototypes for our functions.
struct node *Create_node( int value );
void delete_value(struct node **root, int val_del) ;
void inorder_traversal( struct node *node );
void insert_value( struct node **head, int new_value );
void pre_order_traversal( struct node* node );
struct node* search_by_value(struct node* node, int value);
int random_value_generator(int domain);
For the implementation of the functions:
///\file Functions.c
///\brief C library implementation for BST.
#include <stdio.h>
#include <stdlib.h>
#include "Header.h"
//In this structure we'll be storing our BST.
struct node{
///\struct struct node
///\brief It represents our structure to store our BST.
int data;
struct node *left;
struct node *right;
};
/*-----------------------------------------------------------------------------------------------------*/
/*
Helper function which creates a new node, containing the desired value and setting left and right
pointers to NULL.
*/
struct node *Create_node( int value )
{
///\fn struct node *Create_node(int value)
///\brief Returns a new node, initialised with "value" and 2 NULL pointers, left and right.
///\param value The value which we want to initiliase the newly created node with.
//Creating the new Node and allocating memory to it.
struct node *new_node = (struct node*)malloc(sizeof(struct node));
//Assigning the desired value to the newly created node.
new_node->data = value;
//Setting left and right pointers to NULL;
new_node->left = NULL;
new_node->right = NULL;
return new_node;
};
/*-----------------------------------------------------------------------------------------------------*/
/*
The first traversal method.
*/
void pre_order_traversal( struct node* node )
{
///\fn pre_order_traversal(struct node* node)
///\brief A function used to 'traverse' the tree. It actually is a printing function.
///\param node It represents the starting point of printing.
//Checking if the tree is not empty.
if( node != NULL ) {
///It will print the root, then the left child, then the right child.
//Printing the node.
printf( "%d ",node->data );
//Printing the left child.
pre_order_traversal( node->left );
//Printing the right child.
pre_order_traversal( node->right );
}
}
/*-----------------------------------------------------------------------------------------------------*/
/*
A function which inserts a new node in the tree.
*/
void insert_value( struct node **head, int new_value )
{
///\fn insert_value(struct node **head, int new_value)
///\brief Inserts a new node into our BST.
///\param head This parameter is passed as a double pointer to avoid any conflicts with other fucntions.
/// and represents the starting point of insertion. The function will start searching for the appropriate
/// position to insert the value.
///\param new_value Is the new value which will be assigned to the new node;
//Initialising the pointer.
struct node *current = *head;
//Checking if the the current node is NULL, if it is, we create a new node.
if( current == NULL){
//If the root is NULL, then we create a new new node, containing the new value.
current = Create_node( new_value );
*head = current;
}else{
//Else, if the value is smaller, recur to the left.
if( new_value < current->data ){
insert_value( &current->left, new_value );
}else{
//Else recur to the right.
insert_value( &current->right, new_value );
}
}
}
/*-----------------------------------------------------------------------------------------------------*/
/*
The second traversal method.
*/
void inorder_traversal( struct node *node )
{
///\fn inorder_traversal(struct node* node)
///\brief A function used to 'traverse' the tree. It actually is the second printing function.
///\param node It represents the starting point of printing.
if( node != NULL ) {
///It will print the left child, then the root, then the right child.
//Printing the left child.
inorder_traversal( node->left );
//Printing the root.
printf( "%d ",node->data );
//Printing the right child.
inorder_traversal( node->right );
}
}
/*-----------------------------------------------------------------------------------------------------*/
/*
A function which deletes a node.
*/
void delete_value(struct node **root, int val_del)
{
///\fn void delete_value(struct node **root, int val_del)
///\brief It is the most complex function and it is used to delete a node.
/// There are multiple cases of deletion, such as: a leaf node (a node without any children),
/// a node with a child on the right, a node with a child on the left or a node with 2 children.
//We are starting from root, with two pointers: current and parent.
struct node *current = *root;
struct node *parent;
//We recur on the tree untill we find the node containing the value which we want to remove.
while (current->data != val_del) {
//Moving the parent to root. The root's parent is NULL. (root has no parent)
parent = current;
//If the value is greater the parent's value, recur right.
if (current->data > val_del) {
current = current->left;
}else{
//Else recur left.
current = current->right;
}
}
//Checking if the node is a leaf node. (no children on the left or right)
if ((current->left == NULL) && (current->right == NULL)) {
//Comparing the node's value with the value of its parent.
//If the value is smaller, we remove the left children.
if (current->data < parent->data) {
parent->left = NULL;
}else{
//Else we remove the right child.
parent->right = NULL;
}
free(current);
//Else, we check if it has a child on the left.
}else if (current->right == NULL) {
//Checking if our node is the root.
if(current == *root) {
//Using an aux to free the root, so the memory is not allocated to it anymore .
struct node *aux;
aux = (*root)->left;
free(*root);
(*root) = aux;
//If the node is not the root, we proceed.
}else{
//If the node's parent value is greater the the value of our node. If true, we replace
//the parent's left child with its left succesor and remove (free) the node.
if (current->data < parent->data) {
parent->left = current->left;
free(current);
}else{
//Else, we do the same thing, but for the parent's right child.
parent->right = current->left;
free(current);
}
}
//Else, we check if it has a child on the right.
}else if(current->left == NULL) {
//Checking if our node is the root.
if(current == *root) {
//Using an aux to free the root, so the memory is not allocated to it anymore.
struct node *aux;
aux = (*root)->right;
free(*root);
*root = aux;
//If the node is not the root, we proceed.
}else {
if (current->data < parent->data){
//If the node's parent value is smaller the the value of our node. If true, we replace
//the parent's left child with its right succesor and remove (free) the node.
//It is the mirrored code of the previous case.
parent->left = current->right;
free(current);
}else{
//Else, we do the same thing, but for the parent's right child.
parent->right = current->right;
free(current);
}
}
//Else, the node has 2 children. This is the last case.
}else if( (current->right != NULL) && (current->left != NULL)){
//In order to replace the root, we need to go one step to the right,
//and then all the way to the left, retrieve the smallest value,
//which will replace the root.
struct node *temp = current->right;
int aux;
while (temp->left != NULL) {
temp = temp->left;
}
//This si where we do the swap.
aux = temp->data;
current->data = aux;
temp = temp->right;
}
}
/*-----------------------------------------------------------------------------------------------------*/
/*
Helper function to determine if a value already exists in the tree.
*/
struct node* search_by_value(struct node* node, int value)
{
///\fn struct node* search_by_value(struct node* node, int value)
///\brief It is a function used to check if an element already exists in the tree.
/// If the fucntion returns NULL, it means that the element DOESN'T belong to the tree.
//Checking if the current node is empty or it has the value which we are looking for.
if (node == NULL || node->data == value){
return node;
free(node);
}
//If the value is greater, recur right.
if( value > node->data ){
return search_by_value(node->right, value);
}else{
//Else recur left.
return search_by_value(node->left, value);
}
//Returning NULL if the element wasn't found.
return NULL;
}
/*-----------------------------------------------------------------------------------------------------*/
/*
A simple function to generate random numbers,
between 0 and a domain.
*/
int random_value_generator(int domain)
{
///\fn int random_value_generator(int domain)
///\brief It generates random numbers between 0 and a set domain.
///\param domain It represents the dmain.(the upper boundry for our generation)
return rand()%domain;
}
And finally the the main file:
///\file main.c
///\brief The driver program for our BST library, containing a command line.
#include <stdio.h>
#include <stdlib.h>
#include "Header.h"
//Setting the root to NULL.(empty tree)
struct node *root=NULL;
int main()
{
//Preparing the command line. The choice is like a task selector.
int choice;
//Infinitely recuring until the user decides to exit or there is an error.
do{
//Printing the command line and acquiring the choice.
printf("\nWhat would you like to do ? Select:");
printf("\n1-Add value;\n2-Delete value;\n3-Print In-Order;\n4-Print Pre-Order;\n5-Random;\n6-Exit;");
printf("\n");
printf("\nYour choice:");
scanf("%d",&choice);
switch(choice){
//The first case is used for insertion of a new value.
case 1:{
//Initialising the local values.
int iterations=0,number=0,value=0,iterator=0;
//Setting up a pointer, for later use.
struct node *ptr;
//Acquiring the number of iterations.
printf("\nHow many values would you like to insert? Type a value:");
scanf("%d",&iterations);
//Inserting values as many times as we initiliased "iterations".
while( number < iterations ){
printf("\nValue[%d]=",iterator);
scanf("%d",&value);
//Using the pointer to check if the value already exists.
ptr = search_by_value( root, value );
if( ptr == NULL ){
//In case of ptr = NULL, we add it to the BST.
insert_value(&root,value);
value = 0;
}else{
//Else we ask for another value, without affectig the number of iterations.
printf("\nThe element %d already exists in the tree!",value);
//Resetting the pointer and the vaue to be reused.
value = 0;
ptr = NULL;
//A simple way to keep the loop consistent.
//If we want to insert 10 values and 1 would already exists,
//we would only have 9 values. This way, even if there a values
//already exists, we will still have to insert the appropriate
//nuber of values.
number--;
iterator--;
}
//Incrementing the iterators to prevent an ifinite loop.
number++;
iterator++;
}
//Reseting the iterator to be used later.
iterator=0;
break;
};//end case-1
//The second case is used for deletion.
case 2:{
//Initialising the value.
int d_value=0;
//Acquiering the value we want to delete.
printf("\nWhich value would you like to delete? \nType a value:");
scanf("%d",&d_value);
//Checking if the value exists in the tree.
struct node *ptr = search_by_value( root, d_value );
if( ptr != NULL ){
//If ptr != NULL, it means that the value exists in the tree
// and it can be deleted.
printf("\nDeleting %d !",d_value);
//Deleting the value.
delete_value(&root, d_value);
//Reseting the value for laer use
d_value = 0;
}else if( ptr == NULL ){
//Else the value does not belong to the tree, so it cannot be deleted.
printf("\nThe element %d doesn't belong to the tree!",d_value);
printf("\n");
//Resetting the pointer and the value for later use.
d_value = 0;
ptr = NULL;
}else{
//Else our tree is empty.
printf("\nEmpty Tree!");
}
break;
};//end case-2
//The third case is used for in-order traversal.
case 3:{
printf("\nIn-order traversal:");
inorder_traversal(root);
printf("\n");
break;
};//end case-3
//The fourth case is used for pre-order traversal.
case 4:{
printf("\nPre-order traversal:");
pre_order_traversal(root);
printf("\n");
break;
};//end case-4
//The fifth case is used for randomly inserting value into teh BST.
case 5:{
//Initialising the values.
int iterations=0,number=0,value=0,iterator=0,domain=0;
//Setting up a pointer for later use.
struct node *ptr;
//Acquiering the number of iterations.
printf("\nHow many values would you like to insert? Type a value:");
scanf("%d",&iterations);
//Acquiering the domain for the random generator.
printf("\nPlease type the domain for the randomly generated numbers.");
printf("\nPlease type a value:");
scanf("%d",&domain);
//Iterating until all the values have been successfully inserted.
while( number < iterations ){
//The new value to be inserted is generated using our fucntion.
value = random_value_generator(domain);
//Checking if the values already exists in the tree.
ptr = search_by_value( root, value );
if( ptr == NULL ){
printf("\nInserting %d!",value);
//If ptr = NULL, we can safely insert the value into our BST.
insert_value(&root,value);
//Resetting the value for later use.
value = 0;
}else{
//Else, we cannot insert the value, as it already exists.
printf("\nThe element %d already exists in the tree!",value);
//Resetting the pointer and the value.
value = 0;
ptr = NULL;
//Same trick to insert the exact number of values.
number--;
iterator--;
}
//Incrementing to prevent infinite looping.
number++;
iterator++;
}
//Resetting the iterator for later use.
iterator=0;
break;
};//end case-5
//The sixth case is used to exit the proram at will.
case 6:{
exit(0);
};//end case-6
//The default case occurs in case of error. (hope not)
default :{
printf("\nError!");
exit(-1);
};//end default
}//end switch
}while(1);//end while
return 0;
}
I used double pointers and that got rid of my problems. I hope this will help someone.

Building a Huffman tree from a binary search tree

I am trying to build a huffman tree out of binary search tree. Sadly my code is crashing (Segmentation fault (core dumped)).
This is how the struct is defined:
struct Node
{
unsigned char m_ch;
int m_freq;
struct Node *m_ls,*m_rs;
struct Node *m_hls,*m_hrs;
};
delMin is passed a double pointer to a binary search tree, and deletes from it the leftmost leaf unless it reaches a Node with m_ch==0 and return the deleted Node
I can't find my mistake
struct Node *delMin(struct Node **root)
{
struct Node *current = *root;
struct Node *b4Current;
if (current == NULL)
return NULL;
while (current->m_ls != NULL)
{
if (current->m_ch == 0)
break;
b4Current = current;
current = current->m_ls;
}
if (current->m_ch == 0)
b4Current->m_ls = NULL;
else
{
if (b4Current == NULL)
*root = current->m_rs;
else
b4Current->m_ls = current->m_rs;
}
return current;
}
struct Node *huffman(struct Node *root)
{
struct Node *left;
struct Node *right;
struct Node *tempRoot;
struct Node *huffmanTree;
while (root->m_ch != 0)
{
left = delMin(&root);
right = delMin(&root);
tempRoot = createNode((left->m_freq) + (right->m_freq), 0);
tempRoot->m_hls = left;
tempRoot->m_hrs = right;
insertTree(&root, tempRoot);
}
huffmanTree = tempRoot;
return huffmanTree;
}
EDIT: Added code for the insertTree function called by Huffman
void insertTree(struct Node **root,struct Node *n)
{
if (!*root)
{
*root=n;
return;
}
if(n->m_freq<(*root)->m_freq)
{
insertTree(&((*root)->m_ls),n);
}
else
{
insertTree(&((*root)->m_rs),n);
}
}
In delMin this code section
if (current->m_ch == 0)
b4Current->m_ls = NULL;
else
{
if (b4Current == NULL)
*root = current->m_rs;
else
b4Current->m_ls = current->m_rs;
}
there is no guarantee that b4Current is not NULL.
Consider the case where the root node has m_ch == 0 and m_ls == NULL. You will take the if branch and dereference b4Current.
You need to initialize b4Current with NULL and check for it before any dereference.
You also need to ensure root itself is non-null before initializing current = *root in delMin or dereferencing it in huffman
These should all be initialized to NULL
struct Node *left;
struct Node *right;
struct Node *tempRoot;
struct Node *huffmanTree;
and it is possible, again, to never enter the while loop, leaving tempRoot unset causing a potential segFault in the caller of huffman when you return its value.

Inserting into a Huffman Tree

I am having problems with my huffman tree; when I try to build it I get the nodes in the wrong place. For example, I want my node of weight 2 (with children i:1 and n:1) to go in between a node of m:2 and space:3 but instead it goes right after the previous node that I put in (2 with children of e:1 and g:1).
My question is: how do I insert a node with two children into a huffman tree (I am using a linked list) by priority of both it's weight (aka the sum of both its children) and the symbols of the children (i.e. the right child 'n' comes before the other right child of 'g').
Thanks for your help!
EDIT: also, how can I print off the codes of the tree in alphabetical order; right now I have them printing off by rightmost tree to leftmost
Here is my insert function...
struct node* insert(struct node* head, struct node* temp)
{
struct node* previous = NULL;
struct node* current = head;
printf("entering insert function\n");
// finds the previous node, where we want to insert new node
while (temp->freq > current->freq && current->next != NULL)
{
printf("traversing: tempfreq is %lu and currentfreq is %lu\n", temp->freq, current->freq);
previous = current;
current = current->next;
}
if (current->next == NULL)
{
printf("hit end of list\n");
temp = current->next;
}
else
{
printf("inserting into list\n");
temp->next = current;
previous->next = temp;
}
return head;
}
You've got the insertion wrong when you hit the end of the list. This:
temp = current->next;
should be the other way round, otherwise you just assign NULL to a temporary variable, which won't do anything to your list.
But I think that you also got your special cases wrong. The special case is not "insert at the end", but "insert a new head". Your code will fail if head == NULL. (This might not happen, because you have already a list of nodes without children and you remove nodes until only one node is left, but still.)
A better implementation might therefore be:
struct node *insert(struct node *head, struct node *temp)
{
struct node *previous = NULL;
struct node *current = head;
while (current && temp->freq > current->freq) {
previous = current;
current = current->next;
}
if (previous == NULL) {
temp->next = head;
return temp;
}
temp->next = current;
previous->next = temp;
return head;
}
Note how this code never derefeneces current or previous when they are NULL. Your special case "insert at the end" is handled by the regular code when current == NULL.
Edit: Concerning your request to print the nodes in alphabetical order: There are many possibilities to do that. One is to add a char buffer to your structure that contains the encoding for the letter:
struct node {
int value;
unsigned long freq;
struct node *next;
struct node *left;
struct node *right;
char code[32];
};
Then you create an "alphabet", i.e a list of 256 pointers to nodes of your Huffman tree, initially all null. (You'll need that alphabet for encoding anyways.)
struct node *alpha[256] = {NULL};
Then traverse your tree, pass a temporary char buffer and assign nodes to your alphabet as appropriate:
void traverse(struct node *n, int level, char buf[], struct node *alpha[])
{
if (n == NULL) return;
if (n->value) {
alpha[n->value] = n;
strcpy(n->code, buf);
} else {
buf[level] = '0';
traverse(n->left, level + 1, buf, alpha);
buf[level] = '1';
traverse(n->right, level + 1, buf, alpha);
}
}
When the node has a value, i.e. is childless, the value (ASCII code) is assigned to the alphabet, so that alpha['a'] points to the node with value 'a'. Note that the alphabet does not create nodes, it points to existing nodes.
Finally, print the alphabet:
char buf[32];
traverse(head, 0, buf, alphabet);
for (i = 0; i < 256; i++) {
if (alpha[i] != NULL) {
printf("%c: %s\n", alpha[i]->value, alpha[i]->code);
}
}
Please note that 32 is n arbitrary value that is chosen to be high enough for the example. In a real tree, memory for the code might be allocated separately.

Resources