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?
Related
Hi this is probably a stupid question to ask with a simple solution but I just can't find an answer in the internet.
So I was exercising for an exam and worked on an assignment. The program has the job to find out what the value in the center of a linked list is (if the length of the list is an odd number)
The structdef is:
typedef struct IntList IntList;
struct IntList {
int value;
IntList* next;
};
and my exact problem right now is that I get a segmentation fault when I try using:
list = list->next;
I want to go step by step in a loop to go to the wished list at the nth position (the center) of the linked list.
Someone knows how I have to rewrite this? If you need more Information to help just say so and I will explain more.
With that function I check the length of the list and in my other function I have a loop which only goes to the mid of the length.
int length_list(IntList* list) {
int n = 0;
for(IntList* node = list; node != NULL; node = node->next) n++;
return n;
}
After this loop ends for(IntList* node = list; node != NULL; node = node->next) n++; you surely have node==NULL.
That is not immediatly a problem.
But depending on what you do with the value of n which you return you might have an off-by-one problem. E.g. in a list with exactly one entry (1 is odd after all), the attempt to use a value which is 1 too high could result in an attempt to access a non-existing node.
Because of this I suspect that your problem might be solved by changing the loop to
for(IntList* node = list; node->next != NULL; node = node->next) n++;, so that it ends on the last existing node, instead of behind. The return value will be lower, whatever you do with it will be "more-careful".
That or try something similar with the small code fragment you show and ask about, list = list->next; only do that if the next is not NULL, not if only list is not NULL.
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.
I just stuck with the problem couple of hours, trying to find where my code breaks. I know how to delete linked list but something doesn't work.
First it is a very simple struct with a dataype of int and 2 struct *next and *prev.
struct _list_{
struct _list_ *next;
struct _list_ *prev;
float distance;
}
Now i am making a push_front function and it works great. I get the result that i am looking for. But now i am making pop_front function and something is missing.
The function should return the distance and then remove that list from the linked list but i can't make it do it.
here is the code that i wrote
int pop_front(list** header)
{
float number = (*header)->data;
list *head = *header;
list *remove = head;
// This should check if the pointer is pointing at the first element
while (head->prev != NULL) {
head = head->prev;
}
if (head) {
head = head->next;
free(remove);
remove = head;
remove->prev = NULL;
//if i remove the code below then i get this error
//*** Error in `./double_ended_queue.out': double free or
//corruption (fasttop): 0x0000000001d5a050 ***
//Pop up: 3 pointer: 3 Aborted (core dumped)
*header = *remove;
//And with this code i get a Segmentation fault (core dumped
return number;
}
return 0;
}
Any help would be great, thank you.
P.S. checked all the linked list question here and none helped.
Where are you all getting this homework from? The API sux. Here, someone else did have almost the same homework (link pointing to my answer, which has many issues left): Pointer Dequeue - pointer training
Anyways:
Do you want to return int or float? The element data is type float, your variable "number" too, but your function returns int.
int pop_front(list** header)
{
float number = (*header)->data;
so, here you get the value of the element you're trying to remove, but then ...
list *head = *header;
list *remove = head;
// This should check if the pointer is pointing at the first element
while (head->prev != NULL) {
head = head->prev;
}
... you actually SEARCH for the element to remove.
Obviously, you have to do it the other way round:
int pop_front(list** header)
{
list * head = *header;
while (head->prev) head = head->prev;
now, you should check, weather you need to adjust the *header pointer (and do it right away):
if (*header == head) {
*header = head->next;
}
the only thing to do now is to remove the object from the list, get it's value and free it's memory before return.
head->next->prev = NULL;
float retval = head->data;
free(head);
return retval;
}
As exercise left to you: Make sure, that an empty list doesn't crash ;)
/edit: This will also crash for removal of the last element, so you have two exercises left ;)
I have a homework assignment to implement a binary search tree (create, delete, search). I used the example provided by the teacher but I can't make it work.
Here's my code so far:
void insert_node(int k){
struct node *nodnou,*flow,*parent;
nodnou = (struct node*)malloc(sizeof(node));
nodnou->st = NULL;
nodnou->dr = NULL;
nodnou->nr = k;
if (root==NULL)
{
root = (struct node*)malloc(sizeof(node));
root = nodnou;
}
else
{
flow = (struct node*)malloc(sizeof(node));
parent = (struct node*)malloc(sizeof(node));
flow = root;
parent = root;
while (((flow->st!=NULL) || (flow->dr!=NULL)) && flow!=NULL)
{
if (k<flow->nr)
{
parent = flow;
flow = flow->st;
}
else
{
parent = flow;
flow = flow->dr;
}
}
if (k<flow->nr)
{
parent->st = nodnou;
}
else
{
parent->dr = nodnou;
}
}
}
The way of thinking: This function gets the value of the node we want to insert as the k parameter. The function will only insert the root of the tree (root is global variable).
I think my biggest problem is the while loop that sweeps through the tree to find the spot for the new node.
If I use while (flow!=NULL) it won't work because the flow pointer gets an assignment to something that does not exist. Please help me understand where I am wrong (homework).
Your code has several important flaws, not the least of which is a misunderstanding of how dynamic memory allocation works in C. Never follow a pattern like this:
Type *pointer = malloc(sizeof(Type));
pointer = <<something else>>
It literally leaks memory and gains you nothing in two short lines. This isn't an object-reference based language like Java or C#. Pointers are variables that hold memory addresses. Just like an int can hold an integer, a pointer holds an address. And just like the following example:
int n = 6;
n = 5; //Hmm. Where did the 6 go? Oh yeah, We overwrote it with 5.
You will lose your allocation link doing the same thing with pointers:
struct node *root = malloc(sizeof(*root));
root = nodnou; // memory allocated above is gone. forever leaked.
Pointers are variables. Just like any other variable, they hold values. In the case of a pointer, however, its value is an address. You can have pointers to almost anything in C, including pointers to pointers; variables that hold the address of pointer variables. And I bring them up because they proffer a particularly elegant solution to your insertion requirements.
The following is a general implementation for a binary tree insertion that supports no duplicates in the tree (the code gets even shorter if you allow duplicates). Furthermore, it does this using exactly zero local variables beyond the provided function parameters, and I challenge you to dissect this and determine how it works. It even works on an initially NULL tree root pointer, eliminating the need to special casing if (root) {} else {} logic:
void insert_node(struct node **pp, int k)
{
while (*pp)
{
if (k < (*pp)->nr) // move down left side?
pp = &(*pp)->st;
else if ((*pp)->nr < k) // move down right side?
pp = &(*pp)->dr;
else return; // found the key, no dupes. leave
}
// pp contains the address of the pointer we need to set.
*pp = malloc(sizeof(**pp));
(*pp)->st = (*pp)->dr = NULL;
(*pp)->nr = k;
}
If your tree should support duplicates you need to be consistent about which side they are inserted on, but it shortens the above algorithm considerably:
void insert_node(struct node **pp, int k)
{
while (*pp)
pp = (k < (*pp)->nr) ? &(*pp)->st : &(*pp)->dr;
// pp contains the address of the pointer we need to set.
*pp = malloc(sizeof(**pp));
(*pp)->st = (*pp)->dr = NULL;
(*pp)->nr = k;
}
In either case, invoked on the caller side like this:
struct node *root = NULL;
insert(&root, 5);
insert(&root, 10);
insert(&root, 7);
...etc...
I think you should use while(flow != NULL) and insert your element as flow after that. The way it is right now it will stop in cases when it shouldn't and do weird things whenever it stops. Try working through some examples with pen and paper.
You almost got it. Keep Up!
First you need to understand a bit better memory allocation. In reality, you only need the very first malloc() call in your function. That is the memory you allocate for the node you are appending to the tree during each insert_node() call. All remainingr mallocs you are performing are unnecesary. It seems that you intuitively feel you need to allocate memory for the other pointers you are using, but all of them are temporary and don't require any allocation, just assignment to a valid node before attempting to de-reference them. In fact, those unnecesary allocations will create what is known as a memory leak (memory you request and fail to release) in code like this:
root = (struct node*)malloc(sizeof(node));
root = nodnou;
The second assignmet (root = nodnou) overwrites the result of the previous malloc() call and since you didn't save the overwritten pointer value in any other place, you will no longer be able to release that memory, it will be marked as used for the lifetime of your application!
Next, you can simplify the code that is walking the tree looking for the insertion point.
You seem to worry that flow becomes NULL, but it doesn't matter. The important node is parent. After the while loop ends, it will be pointing to the actual node where the inserted node needs to be linked. Here is a modified version of your code.
void insert_node(int k) {
struct node *nodnou, *flow, *parent;
// this is the only memory allocation that should be done
nodnou = (struct node*)malloc(sizeof(node));
nodnou->st = NULL;
nodnou->dr = NULL;
nodnou->nr = k;
parent = NULL;
if( root == NULL ) {
root = nodnou;
} else {
flow = root;
// We will walk the tree in order until we reach the bottom of the
// tree (flow becomes null). What we are trying to do is to find out
// the node that will become the parent of the new node we are inserting
// It doesn't matter if flow becomes NULL, the important value after the
// while loop ends is parent
while( flow != NULL ) {
// update the current potential parent node
parent = flow;
if( k < flow->nr ) {
// the number we are inserting is lower than the flow node, walk to the left
flow = flow->st;
} else {
// the number we are inserting is greater or equal than the flow node,
// walk to the right
flow = flow->dr;
}
}
// We have reached the bottom, now compare number again with the node that
// will become parent, to find out if we need to link this node to the left
// or to the right of the parent node
if( k < parent->nr ) {
parent->st = nodnou;
} else {
parent->dr = nodnou;
}
}
}
That's it. Try to code the rest of the tree operations and don't hesitate to ask if you become confused. =)
I am trying to figure out an algorithm to delete from the middle of a linked list..
My idea is to traverse the list, find the node right before the node I want to delete, call it Nprev, and set Nprev to Nnext where Nnext is after the node to delete Ndelete.
So Nprev -> Ndelte -> Nnext.
My problem is that I cannot figure out how to traverse this list to find the node before the one I want.
I've been doing this with seg faults because I assign pointers out of range I assume.
Its a very messy algorithm that I have, with many if else statements..
Is there an easier way to do this?
Basically I need to go through the list, apply a function to each node to test if
it is true or false. If false I delete the node.
Deleting first and last is not as hard but middle stumped me.
Please let me know if there are some general ways to solve this problem. I've
been scouring the internet and found nothing I need.
I used this: http://www.cs.bu.edu/teaching/c/linked-list/delete/
but the algorithm before step 4 only deletes the first node in my list
and doesn't do any more.
How can I modify this?
They also give a recursive example but I don't understand it and am intimidated by it.
First you need to find the middle node.
Well take 3 pointers fast, slow, prev
with fast moving with twice the speed of slow and prev storing the address of the node previous of slow.
i.e.
*slow=&head,*fast=&head,prev=Null
traverse the list and when fast=NULL
slow will point to the middle node if number of elements are odd and prev will store the address of node previous of the mid node.
so simply
prev->next=slow->next.
Here an example of something I use to search and remove by index:
Given this struct: (Can also be adapted to other self referencing structs)
struct node
{
S s;
int num;
char string[10];
struct node *ptr;
};
typedef struct node NODE;
Use this to remove an item from somewhere in the "middle" of the list (by index)
int remove_by_index(NODE **head, int n) /// tested, works
{
int i = 0;
int retval = -1;
NODE * current = *head;
NODE * temp_node = NULL;
if (n == 0) {
return pop(head);
}
for (int i = 0; i < n-1; i++) {
if (current->ptr == NULL) {
return -1;
}
current = current->ptr;
}
temp_node = current->ptr;
retval = temp_node->num;
current->ptr = temp_node->ptr;
free(temp_node);
return retval;
}