adding nodes to a binary search tree randomly deletes nodes - c

stack. I've got a binary tree of type TYPE (TYPE is a typedef of data*) that can add and remove elements. However for some reason certain values added will overwrite previous elements. Here's my code with examples of it inserting without overwriting elements and it not overwriting elements.
the data I'm storing:
struct data {
int number;
char *name;
};
typedef struct data data;
# ifndef TYPE
# define TYPE data*
# define TYPE_SIZE sizeof(data*)
# endif
The tree struct:
struct Node {
TYPE val;
struct Node *left;
struct Node *rght;
};
struct BSTree {
struct Node *root;
int cnt;
};
The comparator for the data.
int compare(TYPE left, TYPE right) {
int left_len; int right_len; int shortest_string;
/* find longest string */
left_len = strlen(left->name);
right_len = strlen(right->name);
if(right_len < left_len) { shortest_string = right_len; } else { shortest_string = left_len; }
/* compare strings */
if(strncmp(left->name, right->name, shortest_string) > 1) {
return 1;
}
else if(strncmp(left->name, right->name, shortest_string) < 1) {
return -1;
}
else {
/* strings are equal */
if(left->number > right->number) {
return 1;
}
else if(left->number < right->number) {
return -1;
}
else {
return 0;
}
}
}
And the add method
struct Node* _addNode(struct Node* cur, TYPE val) {
if(cur == NULL) {
/* no root has been made */
cur = _createNode(val);
return cur;
}
else {
int cmp;
cmp = compare(cur->val, val);
if(cmp == -1) {
/* go left */
if(cur->left == NULL) {
printf("adding on left node val %d\n", cur->val->number);
cur->left = _createNode(val);
}
else {
return _addNode(cur->left, val);
}
}
else if(cmp >= 0) {
/* go right */
if(cur->rght == NULL) {
printf("adding on right node val %d\n", cur->val->number);
cur->rght = _createNode(val);
}
else {
return _addNode(cur->rght, val);
}
}
return cur;
}
}
void addBSTree(struct BSTree *tree, TYPE val)
{
tree->root = _addNode(tree->root, val);
tree->cnt++;
}
The method to create a new node:
struct Node* _createNode(TYPE val) {
struct Node* new_node;
new_node = (struct Node*)malloc(sizeof(struct Node*));
new_node->val = val;
new_node->left = NULL;
new_node->rght = NULL;
return new_node;
}
The function to print the tree:
void printTree(struct Node *cur) {
if (cur == 0) {
printf("\n");
}
else {
printf("(");
printTree(cur->left);
printf(" %s, %d ", cur->val->name, cur->val->number);
printTree(cur->rght);
printf(")\n");
}
}
Here's an example of some data that will overwrite previous elements:
struct BSTree myTree;
struct data myData1, myData2, myData3;
myData1.number = 5;
myData1.name = "rooty";
myData2.number = 1;
myData2.name = "lefty";
myData3.number = 10;
myData3.name = "righty";
initBSTree(&myTree);
addBSTree(&myTree, &myData1);
addBSTree(&myTree, &myData2);
addBSTree(&myTree, &myData3);
printTree(myTree.root);
Which will print:
((
righty, 10
)
lefty, 1
)
Finally here's some test data that will go in the exact same spot as the previous data, but this time no data is overwritten:
struct BSTree myTree;
struct data myData1, myData2, myData3;
myData1.number = 5;
myData1.name = "i";
myData2.number = 5;
myData2.name = "h";
myData3.number = 5;
myData3.name = "j";
initBSTree(&myTree);
addBSTree(&myTree, &myData1);
addBSTree(&myTree, &myData2);
addBSTree(&myTree, &myData3);
printTree(myTree.root);
Which prints:
((
j, 5
)
i, 5 (
h, 5
)
)
Does anyone know what might be going wrong? Sorry if this post was kind of long.

it looks like there is an error in your _addNode procedure. It looks like you arent properly storing the new node references in the tree.
struct Node* _addNode(struct Node* cur, TYPE val) {
if(cur == NULL) {
/* no root has been made */
cur = _createNode(val);
return cur;
}
else {
int cmp;
cmp = compare(cur->val, val);
if(cmp == -1) {
/* go left */
cur->left = _addNode(cur->left, val);
}
else if(cmp >= 0) {
/* go right */
cur->left = _addNode(cur->right, val);
}
return cur;
}
the _addnode function was kind of confusing because you were using the return value inconsistently. i believe this version should avoid loosing any nodes.

I don't see an obvious flaw. I would suggest reworking the tree to hold int's or something simpler than your current data. If the tree works fine then at least you know where to look and not worry about the generic tree code.
I suspect _createNode(), can you add that code?

Related

Problem searching in my Binary Search Tree

Problem is function bin_search. it works steady on function insert. However, it gets frozen on function search. I think if it's fine on insert, it should be fine on search, but it isn't. Here is my code...
"bst.h":
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node {
int key;
void *data;
struct Node *left, *right;
void (*destroy)(void *data);
} node;
typedef struct Tree {
node *head;
char name;
} tree;
#define key(node) node->key
#define data(node) node->data
#define left(node) node->left
#define right(node) node->right
#define destroy(node) node->destroy
#define tree_head(tree) tree->head
"functions.c":
#include "bst.h"
int bin_search(node *curr, int key, int cnt, node **found) {
cnt++; printf("cnt+\n");
if (curr == NULL) {
return -1;
} else if (curr->key == key) {
printf("curr_key = key\n"); return cnt;
}
if (curr->key < key) {
printf("curr_key < key\n");
if (curr->right == NULL) {
*found = curr;
return -(cnt + 1);
}
return bin_search(curr->right, key, cnt, found);
} else {
printf("curr_key > key\n");
if (curr->left == NULL) {
*found = curr;
return -(cnt + 1);
}
return bin_search(curr->left, key, cnt, found);
}
}
int insert(tree *root, int key, void *data, void (*destroy)(void *data)) {
if (root->head == NULL) {
node* new_node = (node *)malloc(sizeof(node));
left(new_node) = NULL; right(new_node) = NULL; destroy(new_node) = destroy; key(new_node) = key; data(new_node) = data;
tree_head(root) = new_node;
printf("created first node\n"); return 1;
}
int cnt; node **found;
if ((cnt = bin_search(root->head, key, 0, found)) < 0) {
node* new_node = (node *)malloc(sizeof(node));
left(new_node) = NULL; right(new_node) = NULL; destroy(new_node) = destroy; key(new_node) = key; data(new_node) = data;
if ((*found)->key < key) {
(*found)->right = new_node;
} else {
(*found)->left = new_node;
}
printf("created a node at %d\n", -cnt); return 1;
} else {
printf("already exists in tree"); return -1;
}
}
int search(tree *root, int key, void **data) {
if (root->head == NULL) {
printf("tree is empty\n"); return -1;
}
int cnt; node **found;
if ((cnt = bin_search(root->head, key, 0, found)) < 0) {
return -1;
} else {
if ((*found)->key < key) {
*data = (*found)->right->data;
} else {
*data = (*found)->left->data;
}
return cnt;
}
}
"main.c":
#include "bst.h"
#define MAX_NUM 8
#define MAX_LEGNTH 200
int main() {
// create a tree
tree root; root.head = NULL; root.name = 'a';
FILE *inpt = fopen("list.txt", "r"); char buffer[MAX_LEGNTH];
int count = 0;
while (fgets(buffer, MAX_LEGNTH, inpt) != NULL) {
printf("adding: %d\n", atoi(buffer)); insert(&root, atoi(buffer), buffer, NULL);
count++;
}
fclose(inpt);
int result; void **found;
result = search(&root, 2, found); printf("%d\n", result); // problem in here!!
return 0;
}
what is the problem with my 'search' function. I can't find it.
Besides the utterly non-standard use of sizeof(void), you are not providing a correct out-parameter to search. The point of the found argument is to receive the node pointer if the prospect key was discovered. This...
int cnt;
node **found; // <== LOOK HERE
if ((cnt = bin_search(root->head, key, 0, found)) < 0) {
is not the way to do that. It should be done like this:
int cnt;
node *found = NULL;
if ((cnt = bin_search(root->head, key, 0, &found)) < 0) {
// ^^^^^^
and all references to found thereafter should be through found->, not (*found)->
This mistake is made in three different places in your code. The last one is semi-broken, but still broken nonetheless.
void **found = (void *)malloc(sizeof(void));
int result = search(&root, 2, found);
printf("%d\n", result);
That should use this:
void *found = NULL;
int result = search(&root, 2, &found);
printf("%d\n", result);
Whether the rest of your code is broken I cannot say, and frankly we're not in the business of being an online-debugger. Use your local debugger tools; that's what they're for. But the items listed above are definitely a problem.

Trying to swap 2 adjacent nodes in a linked list in plain C without double pointers

[ WOW - Someone gave me and negative point for my question ]
[ You could at least put a comment why you did not like my question ]
I am stuck.
I remember doing something similar in C++ but for some reason, I can't get it to work in plain C.
I'm trying to swap 2 nodes in a singly linked list.
The starting list is populated as [9,8,7,5,3,2] and I'm trying to bubble sort it, 2 nodes at a time to final list of [2,3,5,7,8,9]
The first iteration(swap) works find with the head. The list returns perfect with [8,9,7,5,3,2]
...but in the second iteration, I loose the 7 and get [8,9,5,3,2] which is WTF and I tried changing the code a bit but I have lost hope.
Can someone actually find what I did wrong. Please no double pointers... if it's only possible with double pointers... Why and How? since I have no idea what are double pointers?
Here is my program so far:
/*
___ENTER TITLE HERE___
Author : Patrick Miron
Date : Oct 20, 2021
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct listNode
{
int data;
struct listNode *next;
} listNode;
typedef struct list
{
struct listNode *head;
struct listNode *tail;
} list;
int isEmpty( const list *l)
{
return (l == NULL);
}
void printList(list *ptrToList, char *title)
{
int counter = 0; //Counter to count the listItem printed so we can add a carriage return at each 5th element.
printf("%s\n", title);
listNode *ptrToCurrentItem = ptrToList->head;
while (ptrToCurrentItem != NULL)
{
counter++;
printf("%d", ptrToCurrentItem->data);
if (counter % 5 != 0)
{
printf(" : ");
}
else
{
printf("\n");
}
ptrToCurrentItem = ptrToCurrentItem->next;
}
}
list *createListWithHeadData(int data)
{
list *ptrList = malloc((sizeof(ptrList)));
listNode *ptrNewNode = malloc(sizeof(listNode));
ptrNewNode->data = data;
ptrList->head = ptrNewNode;
ptrList->tail = ptrNewNode;
return ptrList;
}
void addToFrontList(list *ptrList, listNode *ptrListNode)
{
listNode *tempPtr = ptrList->head;
ptrList->head = ptrListNode;
ptrListNode->next = tempPtr;
}
list *arrayToList(int data[], int size)
{
list *ptrToNewList = createListWithHeadData(data[0]);
for (int i = 1; i < size; i++)
{
listNode *ptrToNewListNode = malloc(sizeof(listNode));
ptrToNewListNode->data = data[i];
addToFrontList(ptrToNewList, ptrToNewListNode);
}
return ptrToNewList;
}
int count(listNode *ptrToHead)
{
if (ptrToHead == NULL)
{
return 0;
}
else
{
return (1 + count(ptrToHead->next));
}
}
void concat(listNode *head1, listNode *head2)
{
assert(head1 != NULL);
if (head1->next == NULL)
{
head1->next = head2;
}
else
{
concat(head1->next, head2);
}
}
void insert(
listNode *p1, // first element
listNode *p2, // second element
listNode *q) // new element to insert between first and second element
{
assert(p1->next == p2);
p1->next = q;
q->next = p2;
}
void delete(listNode *listNode)
{
assert(listNode != NULL);
listNode = NULL;
}
void deleteList(list *list)
{
if (list->head != NULL)
{
list->head = list->head->next;
deleteList(list);
}
}
void swapListNodeWithNext(listNode *ptrToListNode1)
{
//Swap items
listNode *ptrTempNode1 = ptrToListNode1->next;
listNode *ptrTempNode2 = ptrToListNode1->next->next;
//Set the next node from temp1 (ptrToListNode->next->next) to itself
//Could be written as ptrToListNode->next->next = ptrToListNode
ptrTempNode1->next = ptrToListNode1;
ptrToListNode1->next = ptrTempNode2;
ptrToListNode1 = ptrTempNode1;
ptrTempNode1 = NULL;
ptrTempNode2 = NULL;
}
void sortList(list *ptrToListToSort)
{
if (ptrToListToSort->head == NULL)
{
return;
}
listNode *ptrToCurrentItem = ptrToListToSort->head;
listNode *ptrToLastUnsortedItem = ptrToListToSort->tail;
while (ptrToLastUnsortedItem != ptrToListToSort->head)
{
ptrToCurrentItem = ptrToListToSort->head;
while(ptrToCurrentItem->next != NULL)
{
if (ptrToCurrentItem->data > ptrToCurrentItem->next->data)
{
listNode *ptrToHead = ptrToListToSort->head;
if (ptrToCurrentItem == ptrToListToSort->head)
{
ptrToHead = ptrToCurrentItem->next;
}
//Swap items
swapListNodeWithNext(ptrToCurrentItem);
ptrToListToSort->head = ptrToHead;
}
else
{
ptrToCurrentItem = ptrToCurrentItem->next;
}
}
ptrToLastUnsortedItem = ptrToCurrentItem;
}
}
int main(void)
{
printf("\n");
list listOfInt;
int data[6] = { 2, 3, 5, 7, 8, 9 };
list *ptrToNewList = arrayToList(data, 6);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("...End of line...\n");
printf("\n");
return 0;
}
I found a couple issues but the major one was that I did not change my previous ptr's next ( ptrPreviousItem->next) to point to the correct item after the swap. I was only changing the pointer to current item which was just a copy of the head advancing thru my iterations and the previous->next was still pointing to the original item.
Why in the world did it work for my first iteration? Probably because I would not update the last item since it was in correct order it would not get updated after that.
I have included a correct version of my singly linked list bubble sort with pointers. It works and I hope it can help the next person. Believe me alot of the tutorial on the subject barely make the code more readable then identifiers like "a" and "b"...
Oh, and #chqrlie, I don't understand some of the corrections you made in my previous question, some of them are quite unnecessary the others were formated like that when I put the code in brackets and the * in pointers can be put where you want. int* likeThis; int * likeThis; or int *likeThis. But I do usually format it like you with the asterix right against the identifier. I use a space between them when I mean the dereferenced value. Cheers!
/*
Singly Linked List Bubble Sort with Pointers
Author : Patrick Miron
Date : Nov 17, 2021
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct listNode
{
int data;
struct listNode * next;
} listNode;
typedef struct list
{
struct listNode *head;
struct listNode *tail;
} list;
int isEmpty( const list *l)
{
return (l == NULL);
}
void printList(list *ptrToList, char *title)
{
int counter = 0; //Counter to count the listItem printed so we can add a carriage return at each 5th element.
printf("%s\n", title);
listNode *ptrToCurrentItem = ptrToList->head;
while (ptrToCurrentItem != NULL)
{
counter++;
printf("%d", ptrToCurrentItem->data);
if ((counter % 5) != 0 && (ptrToCurrentItem->next != NULL))
{
printf(" : ");
}
else
{
printf("\n");
}
ptrToCurrentItem = ptrToCurrentItem -> next;
}
}
list *createListWithHeadData(int data)
{
list *ptrList = malloc((sizeof(list)));
listNode *ptrNewNode = malloc(sizeof(listNode));
ptrNewNode->data = data;
ptrNewNode->next = NULL;
ptrList->head = ptrNewNode;
ptrList->tail = ptrNewNode;
return ptrList;
}
void addToFrontList(list *ptrList, listNode *ptrListNode)
{
listNode *tempPtr = ptrList->head;
ptrList->head = ptrListNode;
ptrListNode->next = tempPtr;
}
list *arrayToList(int data[], int size)
{
list *ptrToNewList = createListWithHeadData(data[0]);
for (int i =1; i<size; i++)
{
listNode *ptrToNewListNode = malloc(sizeof(listNode));
ptrToNewListNode->data = data[i];
addToFrontList(ptrToNewList, ptrToNewListNode);
}
return ptrToNewList;
}
int count(listNode *ptrToHead)
{
if (ptrToHead == NULL)
{
return 0;
}
else
{
return (1 + count(ptrToHead->next));
}
}
void concat(listNode *head1, listNode *head2)
{
assert(head1 != NULL);
if (head1->next == NULL)
{
head1->next = head2;
}
else
{
concat(head1->next, head2);
}
}
void insert(
listNode *p1, // first element
listNode *p2, // second element
listNode *q) // new element to insert between first and second element
{
assert(p1->next == p2);
p1->next = q;
q->next = p2;
}
void delete(listNode *listNode)
{
assert(listNode != NULL);
listNode = NULL;
}
void deleteList(list *list)
{
if (list->head != NULL)
{
list->head = list->head->next;
deleteList(list);
}
}
void swapListNodeWithNext(listNode *ptrToCurrentNode, listNode *ptrToPreviousNode)
{
//Swap items
listNode *ptrTempNode1 = ptrToCurrentNode->next;
listNode *ptrTempNode2 = ptrToCurrentNode->next->next;
//Set the next node from temp1 (ptrToListNode->next->next) to itself
//Could be written as ptrToListNode->next->next = ptrToListNode
ptrTempNode1->next = ptrToCurrentNode;
ptrToCurrentNode->next = ptrTempNode2;
ptrToCurrentNode = ptrTempNode1;
if (ptrToPreviousNode != NULL)
{
ptrToPreviousNode->next = ptrToCurrentNode;
}
ptrTempNode1 = NULL;
ptrTempNode2 = NULL;
}
void sortList(list *ptrToListToSort)
{
if (ptrToListToSort->head == NULL)
{
return;
}
listNode *ptrToCurrentItem = ptrToListToSort->head;
listNode *ptrToPreviousItem = NULL;
int sizeOfList = count(ptrToListToSort->head);
int innerLoopCounter = 0;
int unsortedElementLeft = sizeOfList;
listNode *ptrToHead = ptrToListToSort->head;
int swappedAtLeastOneItem = 0;
for (int indexOuterLoop = 0; indexOuterLoop < sizeOfList; indexOuterLoop++)
{
ptrToCurrentItem = ptrToListToSort->head;
while((ptrToCurrentItem->next != NULL) && (innerLoopCounter < unsortedElementLeft))
{
// If the data in the next item greater then the current item, swap nodes.
if (ptrToCurrentItem->data > ptrToCurrentItem->next->data)
{
swappedAtLeastOneItem = 1;
// If the current item is the head of the list, and since it will be swap, point to the next item.
if (ptrToCurrentItem == ptrToListToSort->head)
{
ptrToHead = ptrToCurrentItem->next;
}
//Swap items
swapListNodeWithNext(ptrToCurrentItem, ptrToPreviousItem);
//if the ptrToHead has changed, then update the changes.
if (ptrToListToSort->head != ptrToHead)
{
ptrToListToSort->head = ptrToHead;
}
}
// if the nodes do not need to swap, make sure to update the current item and previous items.
else
{
if (ptrToCurrentItem->next != NULL)
{
ptrToCurrentItem = ptrToCurrentItem->next;
}
}
if (ptrToPreviousItem != NULL)
{
ptrToPreviousItem = ptrToPreviousItem->next;
}
else
{
ptrToPreviousItem = ptrToHead;
}
innerLoopCounter++;
}
// If during the first loop no items were swap then exit early all items are already in order.
if (!swappedAtLeastOneItem)
{
printf("**List is already sorted!**\n");
return;
}
unsortedElementLeft--;
innerLoopCounter=0;
ptrToPreviousItem = NULL;
if (ptrToCurrentItem->next == NULL)
{
ptrToListToSort->tail = ptrToCurrentItem;
}
}
}
int main(void)
{
printf("\n");
int data1[6] = {2,3,5,7,8,9};
list *ptrToNewList = arrayToList(data1,6);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("----------------------------\n");
printf("\n");
int data2[8] = {10,11,2,3,5,7,8,9};
ptrToNewList = arrayToList(data2,8);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("\n");
printf("----------------------------\n");
printf("\n");
int data3[10] = {10,11,2,3,5,7,8,1,9,1};
ptrToNewList = arrayToList(data3,10);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("\n");
printf("----------------------------\n");
printf("\n");
int data4[10] = {1,1,1,1,1,1,1,1,1,1};
ptrToNewList = arrayToList(data4,10);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("\n");
printf("----------------------------\n");
printf("\n");
int data5[10] = {21,19,16,13,10,9,6,2,1,1};
ptrToNewList = arrayToList(data5,10);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("\n");
printf("----------------------------\n");
printf("\n");
printf("...End of line...\n");
printf("\n");
return 0;
}
Please note, I did not finish my commenting so don't judge me, I always complete it last.
Hope this helps for anyone having similar issues to me.

Removing items from a tree structure

I have this struct:
typedef struct Tree {
int arrel;
struct Tree *dret;
struct Tree *esq;
unsigned int talla;
} Tree;
With the following methods:
void crearArbre (struct Tree *arbre, int val_arrel)
{
arbre->arrel = val_arrel;
arbre->dret = NULL;
arbre->esq = NULL;
arbre->talla = 0;
}
int inserir (struct Tree *arbre, int valor) //Insert method
{
struct Tree *aux = arbre;
struct Tree *ant = NULL;
while (aux != NULL && aux->arrel - valor != 0)
{
ant = aux;
if (aux->arrel > valor)
{
aux = aux->esq;
}
else
aux = aux->dret;
}
if (aux == NULL)
{
if (ant->arrel > valor)
{
//ant -> esq -> arrel = valor;
ant->esq = (struct Tree *) malloc (sizeof (struct Tree));
ant->esq->arrel = valor;
//crearArbre(ant -> esq ,valor);
}
else
{
ant->dret = (struct Tree *) malloc (sizeof (struct Tree));
ant->dret->arrel = valor;
}
}
arbre->talla += 1;
return 0;
}
int rem (struct Tree *arbre, int valor) //Remove method
{
if (arbre == NULL)
return NULL;
if (valor < arbre->arrel)
{
return rem (arbre->esq, valor);
}
else if (valor > arbre->arrel)
{
return rem (arbre->dret, valor);
}
else
{
int val = arbre->arrel;
arbre = NULL; //Not sure about this
free (arbre); //?
return val;
}
}
void printarArbre (struct Tree *arbre) //Post order printing method
{
if (arbre != NULL)
{
printarArbre (arbre->esq);
printarArbre (arbre->dret);
printf ("%d -> ", arbre->arrel);
}
}
I have been testing the struct by inserting some numbers, find them and finally remove some elements. But, after I remove an element from the tree and calling free(), if I call printarArbre(), in the position that was the element previously removed, if I set (arbre = NULL) and then free(arbre), why is it still being printed? Do I need a flag to indicate whether a node has been removed?
Please see also the comments. The proper way would be:
int rem (struct Tree **arbreIn, int valor) //Remove method
{
struct Tree *arbre= *arbreIn; // shorthand
if (arbre == NULL)
return NULL;
if (valor < arbre->arrel)
{
return rem (&(arbre->esq), valor);
}
else if (valor > arbre->arrel)
{
return rem (&(arbre->dret), valor);
}
else
{
int val = arbre->arrel;
free (arbre); // free the node
*arbreIn = NULL; // set the parent's pointer (esq or dret) to null
return val;
}
}

exc bad access C

I am making a simple BST and, in the add_to_bst() function, it is throwing an error in the first line when referencing the object's value.
CODE
typedef struct node {
int value;
struct node* leftChild;
struct node* rightChild;
} BSTNode;
BSTNode *new_BSTNode(int val) {
BSTNode *this = (BSTNode *) malloc(sizeof(BSTNode));
this->value = val;
this->leftChild = (BSTNode * ) malloc(sizeof(BSTNode));
this->rightChild = (BSTNode * ) malloc(sizeof(BSTNode));
this->leftChild = NULL;
this->rightChild = NULL;
return this;
}
typedef struct bst {
BSTNode * root;
} BST;
BST *new_BST(int root_val) {
BST *this = (BST *) malloc(sizeof(BST));
this->root = (BST * ) malloc(sizeof(BSTNode));
this->root->value = root_val;
// this->root->value = (int *) malloc(sizeof(int));
return this;
}
int node_get(BSTNode *n, int i) {
if (n == NULL) return -1;
if (i == n-> value) return 1;
if (i > n-> value) return node_get(n->rightChild, i);
else return node_get(n->leftChild, i);
}
int bst_get(BST *bst, int i) {
return node_get(bst->root, i);
}
void add_to_bst_node(int i, BSTNode *to) {
int n = to->value; // <--- ERR
printf("\nBST VAL: %d", n);
if (i > n) {
if (to->rightChild == NULL)
to->rightChild = new_BSTNode(i);
else
add_to_bst_node(i, to->rightChild);
} else {
if (to->leftChild == NULL)
to->leftChild = new_BSTNode(i);
else
add_to_bst_node(i, to->leftChild);
}
}
void add_to_bst(BST *tree, int i) {
if (tree->root != NULL) {
add_to_bst_node(i, tree->root);
} else {
tree->root = new_BSTNode(i);
}
}
int main() {
BST *bst = new_BST(10);
add_to_bst(bst, 10);
}
RUN MSG:
0x7fa64fc00690
0x7fa64fc00640
First Val: 10
Process finished with exit code 11
BUILD ERR:
BSTNode *new_BSTNode(int val) {
BSTNode *this = (BSTNode *) malloc(sizeof(BSTNode));
this -> value = val;
this -> leftChild = (BSTNode * ) malloc(sizeof(BSTNode));
this -> leftChild = (BSTNode * ) malloc(sizeof(BSTNode));
return this;
}
This leaves this->rightChild uninitialized and leaves this->leftChild pointing to uninitialized garbage. Neither of these issues is fixed in the code that calls new_BSTnode.
void add_to_bst_node(int i, BSTNode *to) {
int n = to -> value; // <------ ERROR
Not surprising, since to comes from leftChild and rightChild, both of which are broken by the logic of new_BSTNode.
Also:
BST *new_BST(int root_val) {
BST *this = (BST *) malloc(sizeof(BST));
this -> root = (BST * ) malloc(sizeof(BSTNode));
this -> root -> value = root_val;
// this -> root -> value = (int *) malloc(sizeof(int));
return this;
}
This doesn't set this->root->leftChild or this->root->rightChild either, so again, they're garbage that gets passed to add_to_bst_node as to.
The creation of the new node, and insertion into the tree seems incorrect.
A new node should not allocate space for the left and right subtrees. Since new nodes are always added to the extremities, they never have subtrees when new anyway.
BSTNode *new_BSTNode( int val )
{
BSTNode *this = ( BSTNode * ) malloc( sizeof( BSTNode ) );
if ( this != NULL )
{
this->value = val;
this->leftChild = NULL;
this->rightChild = NULL;
}
return this;
}
Using a recursive algorithm when inserting new data allows the code to "walk" the tree, finding the correct place for insertion.
void add_to_bst_node( int value, BSTNode *to )
{
if (to != NULL)
{
if (value > to->value)
{
// Add to child-right subtree
if (to->rightChild == NULL)
{
// right-tree is empty, create it
to->rightChild = new_BSTNode( value );
}
else
{
// add it somewhere on the right-side (recursively)
add_to_bst_node( value, to->rightChild );
}
}
else // if (i <= to->value)
{
// Add to child-left subtree
if (to->leftChild == NULL)
{
// left-tree is empty, create it
to->leftChild = new_BSTNode( value );
}
else
{
// add it somewhere on the right-side (recursively)
add_to_bst_node( value, to->leftChild );
}
}
}
}
A tree is just a node. Making a separate structure for a "tree" is just extra work.
typedef BSTNode BST;
So the creation of a tree, is just the creation of a node:
BST *new_BST( int value )
{
return new_BSTNode( value );
}
The branch in add_to_BST() always chooses the tree->root != NULL if it was initialised error-free. Then the add_to_BST_node() dereferences garbage, (as the other answers have pointed out); here is a graphical representation of the memory allocating functions,
And,
I recommend thinking about what the states are in ones system and drawing them out first so one doesn't fall into an invalid state. Also, if one is doing a constructor, it's a good idea to initialise the entire structure.

why my C structure must add a weird int and it affect the pointer?

this is a binary tree queue problem
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define NUM 10
typedef struct _node
{
int value;
struct _node *left;
struct _node *right;
}TNode,*Tree;
add a *next in q_node is my purpose
other wise , we need to add in the Tree node struct
So, for the sake of doesn't modify the struct of tree
I design a q_node struct to include it
we can use define command to make it as a template.
typedef struct _q_node
{
TNode *t_node;
int length;
struct _q_node *next;
}QNode;
typedef struct _Queue
{
QNode *head;
QNode *tail;
}Queue;
Queue* init_queue()
{
Queue *queue=(Queue*)malloc(sizeof(Queue));
queue->head = queue->tail = NULL;
return queue;
}
int enQueue(Queue *pQueue,TNode *pTNode)
{
QNode *pQNode = (QNode *)malloc(sizeof(QNode));
pQNode->t_node = pTNode;
if(pQueue->head == NULL)
{//when it's empty
pQueue->head = pQNode;
pQueue->tail = pQNode;
}
else
{
pQueue->tail->next = pQNode;
pQueue->tail = pQNode;
}
}
QNode* deQueue(Queue *pQueue)
{
if(pQueue->head == NULL)
{
return NULL;
}
QNode *deNode= pQueue->head;
pQueue->head = pQueue->head->next;
return deNode;
}
TNode* init_TNode(int value)
{
TNode *new_node = (TNode*)malloc(sizeof(TNode));
new_node->value=value;
new_node->left = new_node->right = NULL;
return new_node;
}
//0:empty
int ifEmpty(Queue *pQueue)
{
if(pQueue->head == NULL)
{
//printf("empty tree\n");
return 0;
}
//printf("queue is not empty\n");
return 1;
}
int insert_tree(Tree pTree,int pValue)
{
//found NULL sub tree, then add to his father->left
if(!pTree)
{
return 0;
}
TNode *tNode = init_TNode(pValue);
if(tNode==NULL)
{
printf("create TNode error!\n");
return 0;
}
if(pValue < pTree->value)
if(insert_tree(pTree->left,pValue)==0)
{
//no left child any more,set a new left child to pTree
pTree->left = tNode;
printf("insert :%d\n",pValue);
}
if(pValue > pTree->value)
if(insert_tree(pTree->right,pValue)==0)
{
pTree->right = tNode;
printf("insert :%d\n",pValue);
}
}
Tree creatTree()
{
srand(time(NULL));
Tree root = init_TNode(rand()%100);
printf("root is %d\n",root->value);
int i ;
for(i=1;i<NUM;i++)
{
insert_tree(root,rand()%100);
}
printf("creat tree succuess!Tree heigh is:%d\n",get_tree_height(root));
return root ;
}
int get_tree_height(Tree pRoot)
{
if(!pRoot)
{
return 0;
}
int lh=0,rh=0;
lh = get_tree_height(pRoot->left);
rh = get_tree_height(pRoot->right);
return (lh<rh)?(rh+1):(lh+1);
}
int breath_travel(Tree pRoot,Queue *pQueue)
{
if(!pRoot)
{
return 0;
}
enQueue(pQueue,pRoot);
printf("_______________________\n");
printf("breath begin,enter root:\n");
while(ifEmpty(pQueue)!=0)
{
QNode *qNode = deQueue(pQueue);
//make suer every enQueue Node is not NULL
if(qNode->t_node->left!=NULL)
{enQueue(pQueue,qNode->t_node->left);}
if(qNode->t_node->right!=NULL)
{
enQueue(pQueue,qNode->t_node->right);
}
//print the tree node value
printf("%d ",qNode->t_node->value);
}
printf("\n-----------\nbreath end!\n-----------\n");
return 1;
}
int main()
{
Queue *queue=init_queue();
int i;
ifEmpty(queue);
printf("insert node to queue\n");
Tree root = creatTree();
if(!root)
{
printf("create Tree failed!\n");
return 0;
}
breath_travel(root,queue);
// free(queue);
return 0;
}
if this version can function well in my computer i have to add a unused int
"int length" in the beginning " _q_node" structure , if i don't add it the ifEmpty function cannot find the right position like "pQueue->head == NULL"
why this happen?
Your program has a bug in the insert_tree function. I have added a few comments to your code:
int insert_tree(Tree pTree,int pValue)
{
//found NULL sub tree, then add to his father->left
if(!pTree)
{
return 0;
}
TNode *tNode = init_TNode(pValue);
if(tNode==NULL)
{
printf("create TNode error!\n");
return 0;
}
if(pValue < pTree->value)
if(insert_tree(pTree->left,pValue)==0) // Here the return value is used
{
//no left child any more,set a new left child to pTree
pTree->left = tNode;
printf("insert :%d\n",pValue);
}
if(pValue > pTree->value)
if(insert_tree(pTree->right,pValue)==0) // Here the return value is used
{
pTree->right = tNode;
printf("insert :%d\n",pValue);
}
// No return value here !!
}
As you can see from my comments you miss a return value at the end of the function. Since you use that return value in other places, you program uses some uninitialized return value. That can make your program fail.
BTW: enQueue miss a return value as well.
An advice: Always compile your code with a high warning level and consider all warnings to be errors. In other words - if there are warnings they shall be fixed before running the code.
If you compile using gcc use -Wall to get all warnings
Besides that I think there is a problem with the logic in this function. It uses recursion to find where to insert the new value. In each recursive call you create a new node using TNode *tNode = init_TNode(pValue); but you only use it at the end of the recursion. In other words it seems you have memory leaks.
Further it's unclear how/where you handle the case where pValue is equal to pTree->value
BTW: pValue is a real bad name for an integer as the p makes you think it's a pointer.

Resources