So I am trying to learn how to create a binary tree in C so far I have got this.
void addRecordsToTree(struct date *in, struct date *root) {
if (root == NULL) {
root = malloc(sizeof(struct date));
root = in;
return;
} else {
//Right side of tree processing
if (compareTwoRecords(in, root) >= 0) {
addRecordsToTree(in, root->right);
return;
} else {
root->right = in;
return;
}
//Left side of tree processing.
if (compareTwoRecords(in, root) < 0) {
addRecordsToTree(in, root->left);
return;
} else {
root->left = in;
return;
}
}
}
int main() {
loadFiles();
struct date treeRoot;
struct date *old = malloc(sizeof(struct date));
old = loadContentsIntoHeap(files[file2014]);
addRecordsToTree(&old[0], &treeRoot);
addRecordsToTree(&old[1], &treeRoot);
addRecordsToTree(&old[2], &treeRoot);
addRecordsToTree(&old[3], &treeRoot);
addRecordsToTree(&old[4], &treeRoot);
addRecordsToTree(&old[5], &treeRoot);
printRecord(7, old);
return 0;
}
The problem is when I check the state of the program in a debugger there is just jumbled up data. I think it could be a type problem somewhere, I find pointers are bit of a mind boggling concept. Im not sure if I have used them right. So here is a screen shot of the debugger.
As you can see at the bottom struct called 'old' is the data I am trying to make the tree out of and treeRoot is where I am trying to place it but I can't understand why I get these garbage values.
Also what is up with the memory address of left and right? am I not creating them correctly.
Another observation I made is when I watch my code in the debugger it seems that root is never == NULL and never gets set, why?
You just did the following:
int x = 2;
int y = x;
y = 5;
Is the second line here necessary or the third one. It is a totally illogical program if you did this. You just did the same thing with a pointer instead of integer. You firstly had a pointer to the base address of dynamic memory then you just overwrote it by initializing it the second time.
And, the iterative approach is far better in comparison to the recursive one. I share the code for inserting a node in a binary tree both recursively and iteratively:
void insert(struct node *temp, struct node **root)
{
while (*root != NULL)
root = (*root)->element < temp->element ? &(*root)->left : &(*root)->right;
*root = temp;
}
#if 0
/* Recursive approach */
void insert(struct node *temp, struct node **root)
{
if(*root == NULL)
*root = temp;
else if ((*root)->element < temp->element)
insert(temp, &(*root)->left);
else
insert(temp, &(*root)->right);
}
#endif
void create_node(int x, struct node **root)
{
struct node *temp = (struct node *) malloc(sizeof(struct node));
if (temp == NULL)
printf("Unable to allocate memory. Free some space.\n");
else
{
temp->left = NULL;
temp->right = NULL;
temp->element = x;
insert(temp, root);
}
}
int main()
{
struct node *root = NULL;
create_node(1, &root);
create_node(2, &root);
create_node(3, &root);
return 0;
}
I saw an additional Problem in your "addRecordsToTree"-function:
the IF-block of the
"//Right side of tree processing"
will allways return from the function. regardless wether the "IF"-Expression is true or false.
So your left-leaves of thew tree will never be inserted. So you probalby should check/debug that function.
Related
So I'm a Python programmer and I'm trying to teach myself C. Just as practice, I've been trying to implement a simple Binary Search Tree in C. I've never had to work with memory allocation or pointers before and its been causing a lot of errors.
My program has been giving me exit code -1073740940 (0xC0000374) which I understand means that the heap has been corrupted. It's a bit of a long program, so I just included the offending function.
This insert function is repeatedly called using a for loop to insert the contents of an array into the binary search tree. The array's contents are 5, 4, 6, 3, 7, 2, 8, 1, 9, and 0 (designed to make the tree balanced).
So the function first has 5 passed to it. The pointer called by pBST->listRoot is NULL (pBST is a pointer to a list struct), so insert 5 as a the root node. This works fine. Then 4 is passed to the function. Since there is already a root, it checks the children of that root. 4 is less than 5 so check 5's left child. The pointer for 5's left child is null, so it attempts to insert 4 as a new node. This is the line that crashes the program:
struct Node* pTemp = calloc(1, sizeof(struct Node));
I've tried a couple variations of this line. Here's the kicker: cLion's debugger cannot reproduce this. When I run it through the debugger, it works perfectly. I think it has to do with the fact that the debugger uses the same memory addresses every time for reproducibility. I left the debugging printf statements and added the code for the Node and binarySearchTree structs.
typedef struct Node BSTNode;
struct Node {
BSTNode* parent;
BSTNode* left;
BSTNode* right;
int* data;
};
typedef struct {
BSTNode* listRoot;
int nodeCount;
} binarySearchTree;
void insert(int Value, binarySearchTree* pBST) {
/*
* This function
*/
//====DEBUG CODE============
int debugIterations = 0;
printf("Now inserting %d \n", Value);
//=====END DEBUG CODE=======
//if no root, make it the root
if (pBST->listRoot == NULL) {
struct Node* newNode = calloc(1, sizeof(binarySearchTree));
(*pBST).listRoot = newNode;
(*pBST).listRoot->data;
(*pBST).listRoot->data = Value;
//pBST->listRoot->data = Value;
pBST->listRoot->parent = NULL;
pBST->listRoot->right = NULL;
pBST->listRoot->left = NULL;
return;
} else {
struct Node* pCursor = pBST->listRoot;
while (1){
printf("Iterations: %d \n", debugIterations);
debugIterations++;
//Check if the number is the same
if (pCursor->data == Value){
printf("ERROR: Tried to insert duplicate value into tree");
return;
}
//Is the value > the node?
else if (pCursor->data < Value) {
//DEBUG
printf("== check succeeded, now value > data\n");
// Is the value a Null?
if (pCursor->right == NULL) {
//DEBUG
printf("Running function to insert %d as a new node to the right\n", Value);
//If yes, then insert the value as a nul
//Create Node
struct Node* pTemp = calloc(1, sizeof(binarySearchTree));
pTemp->data = Value;
pTemp->parent = pCursor;
pCursor->right = pTemp;
pTemp->left = NULL;
pTemp->right = NULL;
return;
}
//If no, then iteravely continue.
else {
printf("Iteravely continuing to the right");
pCursor = pCursor->right;
continue;
}
}
//Is the value < the root?
else {
//DEBUG
printf("== check succeeded, now value < data\n");
//Is the value a Null?
if (pCursor->left == NULL) {
//DEBUG
printf("Running function to insert %d as a new node to the left\n", Value);
//If yes, then insert the value where the null is.
//Create Node
struct Node* pTemp = (struct Node*)calloc(1, sizeof(struct Node));
printf("Successfully declared and allocated memory");
pTemp->data = Value;
pTemp->parent = pCursor;
pCursor->left = pTemp;
pTemp->left = NULL;
pTemp->right = NULL;
return;
}
//If no, then iteravely continue
else{
printf("Iteravely continuing to the right");
pCursor = pCursor->left;
continue;
}
}
}
}
}
The line
struct Node* pTemp = calloc(1, sizeof(binarySearchTree));
is wrong. The structure binarySearchTree has one pointer and one int, but the structure struct Node has 4 pointers, so struct Node should be larger than binarySearchTree and this allocation will allocate less space than required, leading to out-of-range access.
It should be:
struct Node* pTemp = calloc(1, sizeof(*pTemp));
or
struct Node* pTemp = calloc(1, sizeof(struct Node));
Also it looks very weird to store the data int Value in the member int* data; with (*pBST).listRoot->data = Value;. It looks like the member should be int, not int*.
I am creating an AVL for an assignment, but when ever I call the rotate right and rotate left functions the executable crashes with no error message. I think it might be due to a NULL pointer exception but I'm not sure.
Here is my code for the rotations:
TNODE *rotate_right(TNODE *y){
TNODE *x=y->left;
TNODE *t2=x->right;
x->right=y;
y->left=t2;
y->height =max(height(y->left),height(y->right))+1;
x->height=max(height(x->left),height(x->right))+1;
}
TNODE *rotate_left(TNODE *x){
TNODE *y=x->right;
TNODE *t2=y->left;
y->left=x;
x->right=t2;
y->height =max(height(y->left),height(y->right))+1;
x->height=max(height(x->left),height(x->right))+1;
}
And here is the insert function I call them in:
void insert(TNODE **rootp, char *name, float score){
TNODE *np = (TNODE *) malloc(sizeof(TNODE));
if (np == NULL) return;
strcpy(np->data.name, name);
np->data.score = score;
np->height = 1;
np->left = NULL;
np->right = NULL;
// 1. Perform the normal BST insertion
if (*rootp == NULL) {
*rootp = np;
return;
}
TNODE *root = *rootp;
if (strcmp(name, root->data.name) < 0 ){
insert(&root->left, name, score);
}
else if (strcmp(name, root->data.name) > 0 ){
insert(&root->right, name, score);
}
else return ;
// 2. update height of this root node
// add your code here
root->height=height(root);
// STEP 3: get the balance factor of this root node
// add your code here
int balance=balance_factor(root);
// STEP 4: re-balance if not balanced
// add your code here
if(balance>1&&balance_factor(root->left)>=0){
rotate_right(root);
}
else if(balance>1&&balance_factor(root->left)<0){
rotate_left(root->left);
rotate_right(root);
}
else if(balance<-1&&balance_factor(root->right)>=0){
rotate_left(root);
}
else if(balance<-1&&balance_factor(root->right)<0){
rotate_right(root->right);
rotate_left(root);
}
}
The code runs fine if I comment out the last part where I have to rotate it so I'm quite sure the problem is there. Thanks in advance for any help.
could you help me?
Program reads words from a file and puts them into binary search tree, but I get "Segmentation fault: 11" when running my print function.
struct node {
char * item;
struct node * left;
struct node * right;
};
struct node * new(char * a) {
struct node * new;
new = (struct node *)malloc(sizeof(struct node *));
new->item = a;
new->left = new->right = NULL;
return new;
}
struct node * insert(struct node * a, char * b) {
if(a == NULL) {
a = new(b);
}
else if (b <= a->item) {
a->left = insert(a->left, b);
}
else {
a->right = insert(a->right, b);
}
return a;
}
void print(struct node * a) {
if (a->left == NULL && a->right == NULL)
printf("%s", a->item);
else if (a->left != NULL)
print(a->left);
else
print(a->right);
}
from main.c :
struct node * root = NULL;
struct node * start;
start = root;
while (fscanf(fp, "%s", temp) != EOF) {
root = insert(root, temp); // insert function works ok
}
print(start);
UPDATE:
I've made a change in main.c:
int i = 0;
while (fscanf(fp, "%s", temp) != EOF) {
root = insert(root, temp);
if (!i) {
start = root;
i = 1;
}
}
Now it doesn't show error, but it prints only the last word from the tree instead of printing it recursively. Any suggestions?
UPDATE #2:
Thank you for your help. Following your suggestions I've made changes to this function:
struct node * new(char * a) {
struct node * new;
char * stringcopy;
stringcopy = malloc(strlen(a) + 1);
strcpy(stringcopy, a);
new = malloc(sizeof(* new));
new->item = stringcopy;
new->left = new->right = NULL;
return new;
}
Now everything works fine.
The original problem was almost certainly that start was NULL since you did not update it when you updated root. (Meanwhile it seems that the whole start is unnecessary; just use root directly.)
The new problem (printing only the last word) is that you are not traversing the tree correctly: your print function only prints if both left and right are NULL, so only a leaf node is ever printed, and furthermore it does not descend into the right branch if there is a left branch.
You could try something like this instead (untested code):
void print(struct node * a) {
if (a == NULL) { return; }
print(a->left);
(void) puts(a->item);
print(a->right);
}
In particular, note that if you are at a non-NULL node, you need to print its item unconditionally, or the complete output will be missing that node.
Another problem seems to be that you are not copying item when you create the node. So if your temp in insert(root, temp) is indeed a temporary object that will be overwritten or freed, all of your items (except possibly the last) will be invalid by the time you try to print them. Instead of assigning new->item = a, do the equivalent of new->item = strdup(a) and then remember to free it when you free the node.
(strdup is not in the C standard library, but it is easy to implement: allocate enough space for the string, including NUL terminator, and copy.)
Also, the comparison b <= a->item is almost certainly not doing what you expect it to; see strcmp.
I've been stuck on the insertion part of the binary search tree. I get so confused with nested structs. The basic idea of this program is to create a bst that is able to hold names and double values which get stored by value (obviously).
Example: I want to store
Jane 3.14
John 3.233
Luke 6.4
Mike 1.4
so the bst would look like
3.14
/ \
1.4 3.233
\
6.4
however I'm having trouble with the insertHelper recursion portion of the code. The hash table is a bonus part of the code that I'll try implementing at a later time. Thank you for your help!
typedef struct name_val // holds name and value
{
char *name;
double value;
}NAME_VAL;
typedef struct node //binary search tree
{
NAME_VAL *nV;
struct node *left;
struct node *right;
}NODE;
struct tmap_struct //handle for bst and hashtable
{
int nL; //nodes on left
int nR; //nodes on right
NODE *root;
NODE **table;
};
int tmap_insert(TMAP_PTR hashTree, char * name, double val)
{
if(hashTree->root == NULL)
{
NODE *bst = (NODE *)malloc(sizeof(NODE));
NAME_VAL *root = (NAME_VAL *)malloc(sizeof(NAME_VAL));
bst->nV = root;
bst->nV->value = val;
strcpy(bst->nV->name, name);
hashTree->root = bst;
hashTree->nL = 0;
hashTree->nR = 0;
}
else
insertHelper(hashTree->root, val, name);
}
void insertHelper(TMAP_PTR hashTree, int val, char * name)
{
if(val < hashTree->root->nV->value)
{
if(hashTree->root->left == NULL)
{
hashTree->root->left = (NODE *)malloc(sizeof(NODE));
hashTree->root->left->nV = (NAME_VAL *) malloc(sizeof(NAME_VAL));
strcpy(hashTree->root->left->nV->name, name);
hashTree->root->nV->value = val;
(hashTree->nL)++;
}
else
insertHelper(hashTree->root->left, val, name);
}
else
{
if(hashTree->root->right == NULL)
{
hashTree->root->right = (NODE *)malloc(sizeof(NODE));
hashTree->root->right->nV = (NAME_VAL *)malloc(sizeof(NAME_VAL));
strcpy(hashTree->root->left->nV->name,name);
hashTree->root->nV->value = val;
(hashTree->nR)++;
}
else
insertHelper(hashTree->root->right, val, name);
}
}
I doubt this compiles. Is that the problem you're having?
From what I can see, you have declared insertHelper with the wrong type for its first parameter. It should take NODE* values, not TMAP_PTR values. That's because you always call it with nodes out of your tree.
So the first part of the function should look like this:
void insertHelper(NODE *node, int val, char * name)
{
if(val < node->nV->value)
{
if(node->left == NULL)
{
node->left = (NODE *)malloc(sizeof(NODE));
node->left->nV = (NAME_VAL *) malloc(sizeof(NAME_VAL));
strcpy(node->left->nV->name, name);
node->left->nV->value = val;
}
else
insertHelper(node->left, val, name);
}
//.....
Note that I removed the line:
(hashTree->nR)++;
It hardly even makes sense to track this information, unless maybe you do it at the node level.
But if you must, you could have insertHelper recursively return a positive or negative value to indicate what side it inserted on. But that doesn't makes sense. What is it on the right of? You may have inserted it on the right of a node that was in the left half of the tree.
If you store this information on each node, you can recursively update the node above as you return from insertHelper. Maybe that's what you were trying to do. Balanced tree implementations do something similar - AVL trees store the maximum depth of the tree at a node and use that to do branch rotations for rebalancing.
You'll have to adapt mine(It's almost standard C besides the unneeded template and class), but it's a similar algorithm: (I believe, I didn't look at any source for my own purposes.)
template<typename T>
class BST {
protected:
typedef struct node_t {
struct node_t * dir[2];
T data;
} node;
node * root;
void insert_node(node * active_node, T data){ //call with node *root;
int next = data < active_node->data ? 0 : 1;
if(active_node->dir[next] == NULL){
active_node->dir[next] = new node;
active_node->dir[next]->dir[0] = NULL;
active_node->dir[next]->dir[1] = NULL;
active_node->data = data;
} else
insert_node(active_node->dir[next], data);
}
public:
BST() : root(new node){root->dir[0] = NULL; root->dir[1] = NULL; root->data = 0;}
~BST(){}
}
Disclaimer: This is for an assignment. I am not asking for explicit code answers, only help understanding why my code isn't working.
I am trying to implement a basic Binary Search Tree, but I am having problems with my _addNode(...) function.
Here's the problem. When I walk through my code with the debugger, I notice that leaf nodes are created infinitely on both sides (left and right) so aside from the creation of the root, there is never any point when a leaf node is NULL. The problem is that I am asking my program to create a new node whenever it finds a NULL value where a leaf would be. Therefore, if there are never any NULL values, there will never be any new leaves created, right?
The other issue I'm running into is with my compare(...) function. Stepping through it in the debugger shows it to iterate through the function several times, never actually returning a value. When it returns to the calling function, it drops back into the compare(...) function and loops infinitely. Again, I don't know why this is happening considering I have valid return statements in each if statement.
Here is all the code you'll probably need. If I left something out, let me know and I'll post it.
struct Node {
TYPE val;
struct Node *left;
struct Node *right;
};
struct BSTree {
struct Node *root;
int cnt;
};
struct data {
int number;
char *name;
};
int compare(TYPE left, TYPE right)
{
assert(left != 0);
assert(right != 0);
struct data *leftData = (struct data *) left;
struct data *rightData = (struct data *) right;
if (leftData->number < rightData->number) {
return -1;
}
if (leftData->number > rightData->number) {
return 1;
} else return 0;
}
void addBSTree(struct BSTree *tree, TYPE val)
{
tree->root = _addNode(tree->root, val);
tree->cnt++;
}
struct Node *_addNode(struct Node *cur, TYPE val)
{
assert(val != 0);
if(cur == NULL) {
struct Node * newNode = malloc(sizeof(struct Node));
newNode->val = val;
return newNode;
}
if (compare(val, cur->val) == -1) {
//(val < cur->val)
cur->left = _addNode(cur->left, val);
} else cur->right = _addNode(cur->right, val);
return cur;
}
Edit: Adding the below function(s)
int main(int argc, char *argv[])
{
struct BSTree *tree = newBSTree();
/*Create value of the type of data that you want to store*/
struct data myData1;
struct data myData2;
struct data myData3;
struct data myData4;
myData1.number = 5;
myData1.name = "rooty";
myData2.number = 1;
myData2.name = "lefty";
myData3.number = 10;
myData3.name = "righty";
myData4.number = 3;
myData4.name = "righty";
/*add the values to BST*/
addBSTree(tree, &myData1);
addBSTree(tree, &myData2);
addBSTree(tree, &myData3);
addBSTree(tree, &myData4);
/*Print the entire tree*/
printTree(tree);
/*(( 1 ( 3 ) ) 5 ( 10 ))*/
return 1;
}
Maybe you could try setting right and left to NULL right after malloc:
struct Node * newNode = malloc(sizeof(struct Node));
newNode->left = NULL;
newNode->right = NULL;
Check this line here (or the corresponding for left):
cur->right = _addNode(cur->right, val);
If cur->right == 0, it's fine. But if cur->right != 0, the node that was sitting there will be replaced by the return value of _addNode, which ultimately is not a whole branch, but just one node.
I like to explicitly 0-out values in a struct after a malloc using memset(newNode, 0, sizeof(struct Node)). Others might disagree.