Recursive Approach is not working on Binary Search Tree - c

I have a C code template, and I need to complete it to have a binary search tree and then improve it to be an AVL tree. In the code template, there were given to me some declarations of necessary functions and the definition of struct. But I am having troubles with the BST.
Here is the struct which is given to me in the code template;
typedef struct NODE_s *NODE;
typedef struct NODE_s
{
NODE right;
NODE left;
unsigned long long data;
int height;
} NODE_t[1];
Firstly, I tried to write a node initializer function. Simply, it takes an unsigned long long data as parameter, and uses it to initialize a new unique node, then returns it. What I am confused here is the usage of the name of the struct in memory allocation part. Here is the function;
NODE node_init(unsigned long long data)
{
NODE newNode = (struct NODE_s*)malloc(sizeof(struct NODE_s));
newNode->data = data;
newNode->right = NULL;
newNode->left = NULL;
newNode->height = 1;
return newNode;
}
Thereafter, I tried to code a recursive insertion function for my tree. It simply takes two parameters. I showed my thinking way on writing these codes with the comment lines to make it clear for you.
NODE avl_insert_recursive(NODE node, unsigned long long data){
if( node == NULL){ // if the node is NULL, then assign the data directly to it.
return(node_init(data)); // call the node initializer function, initialize a node with the value of data
}
if( data < node->data ){ // if the data is smaller than the node's data
node->left = avl_insert_recursive(node->left, data);
}else if( data > node->data){ // if the data is bigger than the node's data
node->right = avl_insert_recursive(node->right, data);
}else{ // if equality occurs, directly return the node itself.
return node;
}
Lastly, to test my tree, I have a function over there. But, for the purpose of simplifying it in my question, I am going to pick over the necessary lines;
NODE node = node_init(NULL); // firstly, initializing an empty node for a recursive tree
int i = 0;
unsigned long long number; // The numbers will be stored in it.
fp = fopen(fname, "r+"); // There will be a .txt consist of unsorted long numbers.
for(i = 0; i<n; i++){
fscanf(fp, "%llu\n", &number); // taking numbers line by line
node = avl_insert_recursive(node,number); // inserting each number to our tree
}
fclose(fp);
So as a conclusion, I shared the necessary lines and functions above and tried to simplify it as much as I can. The problem is, this code does not work. The function named avl_insert_recursive is not working recursively and stucking after 2-3 loop, as I checked it with printf statements. So if anyone out there can spend their time to read these lines of codes and help me to solve this problem, I will be very appreciated. Thanks for help.

You're missing return statements from some of your paths in avl_insert_recursive. This results in Undefined Behavior.

Related

How to get C code to print to output file?

I have a code that sorts a list, I can get it to sort when the list is hardcoded. I am now attempting to implement getting the list from an input file and running it the same way through the code then printing it to an output file. I am trying to get a scanned list from an input file to go through what I have (that is working) for sorting and for the result to be printed to an output file.
You have assigned *tmp to head. But I can see that head had always been NULL. So the loop is never entered, and nothing is being inserted to the list.
So what we'd need to do it first initialize head to a node instance
typdef struct node
{
char* data;
struct node *prev;
struct node *next;
}node;
head = malloc(sizeof(node));
then we assign it data.
head->attribute = value;
finally we set this pointer location value to our tmp pointer as well.
tmp = head;
no we can proceed with our loop
strings in C are represented as an array of chars, whose stored location points to the first element of the char array. the array must also end with a NULL chat '\0'. note that strlen(str) will return length of string without the NULL char so you must add 1 while mallocing to take this into sconsideration. i would advise not messing with strings unless absolutely necessary. by that I mean trying to manually manipulate them. this will introduce another set of problems not related to what we're working on in general. we should just use strncar(), strncpy() methods until c style strings become completely intuitive.
I hope I understood right your question. I tried to fix the program like it will read a file and make a list of the data in the file.
I fixed some issues;
For the transverse function, i added a for loop and printed the data using %c.
while (temp != NULL) {
for(i=0; temp->data[i]!='\0'; i++) {
printf("%c\n", temp->data[i]);
}
temp = temp->next;
}
I changed the insertAtEnd function like this;
void insertAtEnd(FILE* f, char* data)
And naturally, in main function, calling this function changed like;
insertAtEnd(ifp, result[i]);
By the way for the following statement, my complier wanted me to express the temp as char, it said it was the first use of this. It also seems like you entered a space after &.
insertAtEnd(ofp, &temp);
I added the following statements to the main function;
argc -= optind;
argv += optind;
I also changed this ifp= fopen(ifilename, "r"); statement with this ifp= fopen("ifilename.txt", "r");statement. I opened a text file named ifilename.txt and wrote some data there.
EDIT:
Ok so if you want to print the strings to an output file and you want to print the words in the lines individually, you will change the code doing the following things:
I changed the struct's data with an array, gave it an expected maximum line length with a sharp defined MAX_LEN;
struct node
{
char* data[MAX_LEN];
struct node *prev;
struct node *next;
};
I changed the insertAtEnd function again because I scanned the file in main function, made an array of the strings, sent it to this function and added it to the end of the list. I used this piece of code in main fuction:
char* result[count];
char* temp = (char*)malloc(sizeof(char));
while (fgets(temp, sizeof(temp), ifp))
{
result[count] = (char*)malloc(sizeof(char)*20);
strcpy(result[count], temp);
insertAtEnd(result, count);
count++;
}
count is the number of strings in the file. I also sent this number to insertAtEnd function;
void insertAtEnd(char* data[], int size)
{
//Create a new node
struct node *newnode = (struct node*)malloc(sizeof(struct node));
newnode->data[size] = data[size];
if (newnode->data[size] != NULL) {
...
I wanted to use the output file you opened in the main function, so I sent this file and sent the count -number of strings- to the printing function transverse like this;
void traverse(FILE *of, int size)
{
int i;
// List is empty
if (head == NULL) {
printf("\nList is empty\n");
return;
};
// Else print the Data
struct node* temp;
temp = head;
while (temp != NULL) {
for(i=0; i<size; i++) {
fputs(temp->data[i], of);
temp = temp->next;
}
fprintf(of, "\n");
}
}
Also in main function, calling this function will be changing like;
traverse(ofp, count);

Creating and displaying linear linked list in C(Recursively)

I'm trying to creating linear linked list recursively with c language,
but keep sticking from here and the code is not working with the error "Linker Tools Error LNK2019". Sadly i can't understand what's the matter. Here is my code.
Thanks for your big help in advance.
#include <stdio.h>
#include <stdlib.h>
struct node
{
char num; //Data of the node
struct node *nextptr; //Address of the next node
};
typedef struct node element;
typedef element *link;
link head;
void displayList(); // function to display the list
int main()
{
char s[] = "abc";
link stol(s);
{
link head;
if (s[0] == '\0')return(NULL);
else {
head = (link)malloc(sizeof(element));
head->num = s[0];
head->nextptr = stol(s + 1);
return(head);
}
}
printf("\n\n Linked List : To create and display Singly Linked List :\n");
printf("-------------------------------------------------------------\n");
displayList();
return 0;
}
void displayList()
{
link tmp;
if (head == NULL)
{
printf(" List is empty.");
}
else
{
tmp = head;
while (tmp != NULL)
{
printf(" Data = %d\n", tmp->num); // prints the data of current node
tmp = tmp->nextptr; // advances the position of current node
}
}
}
You redefine a link object called head in your main() function. It hides the global head variable.
Removing the definition inside main would fix your problem, but you should consider passing a link* as a parameter to your displayList function in any case.
I've just noticed this statement return(head); in main(). You program exits prematurely as a result as well.
Everytime I look at your app, I find more issues. If I were you, I'd start by creating a function that adds a node to the list. It's much easier to add new nodes to the front of the list, so you should try that first. Try adding to the tail once you get this running. Adding to the tail is very similar, but you have to 'walkthe list first to get to the last element, exactly as you already do indisplayList()` Another way is keeping the address of the last node* you've added to the list. Like I said, it adds a bit of complexity, so get it working with addToHead first.
void addToHead(link* l, node* n)
{
n->nextptr = l->nextptr;
l->nextptr = n;
}
in your main, you can allocate one new node at a time, as you already do with malloc(). Initialize its contents num with an integer, and let addToHead deal with the pointer stuff. Your use of pointers is terrible, but lists are quite easy, and addToList pretty much shows what can and what should be put in pointers - namely other pointers.
You can remove almost everything in main() before the first printf. You'll have to
start loop:
write a prompt so the user knows what to do using printf()
read input from user using scanf("%d", &n), or equivalent.
break from the loop if user enters a negative value.
malloc() a new node
set its data num = n
call addToHead to add the node.
Loop until user enters an empty string, or -1.
That should take about 8 to 10 lines of code. if in doubt, you will easily find documentation on scanf, with google or on http://en.cppreference.com/w/c.

Malloc of pointers in structs + pointer arithmetic + free() + linkedList

I'm trying to implement a linked-list data structure which each node has a identifier key, some data of variable length (malloc), and a pointer to the next node. Now I want to have 3 functions which respectively: sets a new node to the front of the list, prints the values of a given node using identifier key, and deletes a given node.
The struct I have for the node is as follows:
struct node {
char key[5];
int* data;
node* next;
};
struct node* headNode = NULL;
I have questions regarding each of functions. I will list the function codes I have and ask questions regarding that specific function below:
The code for my set function:
void command_set (char key[], int val[], int numOfVal){
struct node* temp = (node*)malloc(sizeof(node));
strcpy(temp->key, key);
temp->data = (int*)malloc(numOfVal*sizeof(int));
*(temp->data) = *(val);
temp->next = entry_head;
entry_head = temp;
return;
}
Now I have one question regarding this function:
1) Is my method of storing the data valid? i.e. "temp->data = (int*)malloc(numOfValuessizeof(int));" + "(temp->data) = *(val);". What I'm trying to do is dynamically allocate some memory, then store the given values as my node's data in that memory.
The code for my print function:
void printNode (char key[], int numOfVal){
int i;
struct node *currentNode = headNode;
while(currentNode->next!=NULL){
if(!strcmp(currentNode->key,key) ){
for(i=0; i<numOfVal; i++){
printf("%d ",*((currentNode->data)+i));
}
return;
}
currentNode = currentNode->next;
}
I have a one question regarding this function:
2) The data of a node is a list of integers, so does my way of printing out each integer actually work? i.e. "*((currentNode->data)+i)". What I'm trying to do is by using pointer arithmetic I print all the ints stored under data.
The code for my delete function:
void deleteNode (char key[]){
struct node *currentNode = headNode;
struct node *prevNode = headNode;
while(currentNode->next!=NULL){
if(!strcmp(currentNode->key,key) ){
prevNode->next = currentNode->next;
free(currentNode->data);
free(currentNode->next);
free(currentNode);
return;
}
prevNode = currentNode;
currentNode = currentNode->next;
}
I have two questions regarding this function:
3) Am I "deleting" the nodes properly? By using free(). Is this the way to do it?
4) Is this how you link up nodes after deletion? By setting the next pointer to another node.
Please assume that malloc will not return NULL for simplicity. Also note that I have simplified my actual code, else there is way too much to post, so there might be slight errors. You may also assum that the while loops will always work (i.e. there will not be a case where (currentNode->next==NULL). The main point of this post are my questions regarding whether the method of doing something is correct.
An example of the program would be:
-set ex1 2 3 4 5
-get ex1
2 3 4 5
-set ab 32 112
-get ab
32 112
Thanks in advance.
strcpy(temp->key, key);
For the the purpose of your program, this is probably ok, but you should use strncpy(temp->key,key,5) to be safe. Or at least check the length of key to make sure it fits.
*(temp->data) = *(val);
This only sets the first index in the array. You should use memcpy here.
memcpy (temp->data,val, sizeof (int) * numOfVal);
Your print function prints the first element that doesn't match. Did you mean to do the opposite?
Your delete function does the thing. It finds the first node that doesn't match.
You also don't want to free currentNode->next;

Binary Tree Insertion Error

I looked at several BST Insert articles but none of them were structured the same as mine or encountered the same problem.
My problem is my Binary Tree isn't being built correctly. It's really strange because I'm copy+pasting most of the code from a previous project where it works fine, the only difference is the data the nodes contain, and the condition for looping through the tree uses strcmp rather than integer comparison.
This is my insert function:
//insert parameter node data into a Binary Tree
TreeNodePtr insertNode(BinaryTree bst, Record d)
{
//if root is null insert into root
if(bst.root == NULL)
{
bst.root = (TreeNodePtr) malloc(sizeof(TreeNode));
bst.root->data = d;
bst.root->left = NULL;
bst.root->right = NULL;
return bst.root;
}
//we need to traverse the tree so declare a pointer "curr" to do so
TreeNodePtr curr = (TreeNodePtr) malloc(sizeof(TreeNode));
curr = bst.root;
//loop until we find an appropriate empty space or a match (no duplicates)
while (strcmp(d.lastName, curr->data.lastName) != 0)
{
if (strcmp(d.lastName, curr->data.lastName) < 0)
{ // if left
if(curr->left==NULL)
{
curr->left = (TreeNodePtr) malloc(sizeof(TreeNode));
curr->left->data = d;
curr->left->left = NULL;
curr->left->right = NULL;
return bst.root;
}
curr=curr->left;
}
else if (strcmp(d.lastName, curr->data.lastName) > 0)
{ // try right
if(curr->right==NULL)
{
curr->right = (TreeNodePtr) malloc(sizeof(TreeNode));
curr->right->data = d;
curr->right->left = NULL;
curr->right->right = NULL;
return bst.root;
}
curr=curr->right;
}
}
return bst.root;
}
Here is the code in the main function which uses the insert function to build the tree (note that records is a correctly populated array, each index containing one node's data):
//declare BST and build it
BinaryTree phoneTree;
phoneTree.root = NULL;
for (int i=0; i < sizeof(records) / sizeof(Record); i++)
{
Record tmpRecord;
tmpRecord.firstName = records[i].firstName;
tmpRecord.lastName = records[i].lastName;
tmpRecord.phoneNum = records[i].phoneNum;
phoneTree.root = insertNode(phoneTree, tmpRecord);
}
And for reference, here are the tree structs:
//phone data record struct
typedef struct
{
char *firstName;
char *lastName;
char *phoneNum;
}Record;
//define the tree node which contains the data
typedef struct treeNode
{
Record data;
struct treeNode *left,*right;
}TreeNode,*TreeNodePtr;
//define binary tree struct
typedef struct
{
TreeNodePtr root;
}BinaryTree;
I've been staring at the program that works and comparing it to this program for about 5 hours now and I can't figure out what's going wrong. I know the tree isn't populated correctly because if i try to print phoneTree.root->right.data or phoneTree.root->left.data attributes, the program crashes. In the program I'm borrowing the code from, these attributes are printed without error. The root is still inserted correctly and it's attributes can be printed.
Any insight as to what I'm doing incorrectly is greatly appreciated.
There is one definite mistake, which could be causing you problems. You need to pass "bst" by reference, so that the function can modify "bst.root". Try rewriting the function as:
TreeNodePtr insertNode(BinaryTree* bst, Record d)
and use "bst->" in place of "bst."
You said that it worked with integers. Now that may be a clue to another mistake. Your record contains only pointers to strings. Do these pointers remain valid throughout the lifetime of the tree? Maybe you need to make copies of the strings within the record.
Couple of other minor things:
//we need to traverse the tree so declare a pointer "curr" to do so
TreeNodePtr curr = (TreeNodePtr) malloc(sizeof(TreeNode));
curr = bst.root;
malloc is redundant here, the result is immediately overwritten.
And:
}
else if (strcmp(d.lastName, curr->data.lastName) > 0)
{ // try right
you can replace this with "} else {" as you already did this strcmp operation.
Thanks for all the great tips, they've all contributed to my understanding of memory management in C.
Strangely, I found the problem is actually rooted in my array for loop. I found the method of using sizeof(array) / sizeof(arraydatatype) from multiple sources on the internet and this site so I attempted it, but it doesn't work the way I tried. In:
for (int i=0; i < sizeof(records) / sizeof(Record); i++)
{
Record tmpRecord;
tmpRecord.firstName = records[i].firstName;
tmpRecord.lastName = records[i].lastName;
tmpRecord.phoneNum = records[i].phoneNum;
phoneTree.root = insertNode(phoneTree, tmpRecord);
}
I replaced "i < sizeof(records) / sizeof(Record)" with just"i < 3" (array should only have 3 elements at this point), and everything worked as it should. It's a really dumb source of the problem, but funny that despite all the answers provided none mentioned it :p
Since we're already here, can anyone explain why that was going wrong / how to properly loop through an array in such a manner?

Unable to reverse a linked list

I was trying to reverse a linked list, however whenever I execute the following function, I get only the last element. For example, if the list contained 11,12,13 earlier. After executing the function, it contains only 13. Kindly point out the bug in my code
void reverselist() {
struct node *a, *b, *c;
a = NULL;
b = c = start;
while (c != NULL) {
c = b->next;
b->next = a;
a = b;
b = c;
}
start = c;
}
Doesn't your loop guard insure that start is null?
If you aren't using start to identify the first element of the list, then the variable you ARE using is still pointing to what WAS the first element, which is now the last.
c is a helper pointer.
void reverselist()
{
struct node *a, *b, *c;
a=NULL;
b=start;
while(b!=NULL)
{
c=b->next
b->next=a;
a=b
b=c
}
start=a;
}
// You should assume that Node has a Node* called next that
// points to the next item in a list
// Returns the head of the reversed list if successful, else NULL / 0
Node *reverse( Node *head )
{
Node *prev = NULL;
while( head != NULL )
{
// Save next since we will destroy it
Node *next = head->next;
// next and previous are now reversed
head->next = prev;
// Advance through the list
prev = head;
head = next;
}
return previous;
}
I would have made a prepend function, and done the following:
struct node* prepend(struct node* root, int value)
{
struct node* new_root = malloc(sizeof(struct node));
new_root->next = root;
return new_root;
}
struct node* reverselist(struct node* inlist)
{
struct node* outlist = NULL;
while(inlist != NULL) {
struct node* new_root = prepend(outlist, inlist->value);
outlist = new_root;
inlist = inlist->next;
}
return outlist;
}
Have not tested this, but guess you grasp the idea of it. Might be just your variable names, which don't describe anything, but I think this approach is cleaner, and easier to understand what actually happens.
EDIT:
Got a question why I don't do it inplace, so I'll answer it here:
Can you do it inplace? Are you sure you don't wish to keep the
original list?
Do you need to do it inplace? Is the malloc to time consuming/is this a performance critical part of your code? Remember: premature optimization is the root of all evil.
Thing is, this is a first implementation. It should work, and not be optimized. It should also have a test written before this implementation is even thought of, and you should keep this slow, un-optimized implementation until the test passes, and you have proved that it's to slow for your use!
When you have a passing unit test, and proven the implementation to be to slow, you should optimize the code, and make sure it still passes the test, without changing the test.
Also, is it necessary inplace operations which is the answer? What about allocating the memory before reverting it, this way you only have one allocation call, and should hopefully get a nice performance boost.
This way everyone is happy, you have a cleaner code and avoid the risk of having Uncle Bob showing up at your door with a shotgun.

Resources