How to insert a node in a BST without using CC_TREE**? - c

So I have a piece of code, where I have to add a node to a BST. My struct is the following:
typedef struct _CC_TREE {
// Members
int Value;
struct _CC_TREE* LChild;
struct _CC_TREE* RChild;
} CC_TREE;
The insert function in the header file looks like this:
int TreeInsert(CC_TREE *Tree, int Value);
where I have to return the status of the insert.
I tried doing it with another function and add it to the Tree
CC_TREE* InsertNewNode(CC_TREE* Tree, int Value)
{
if (NULL == Tree)
{
Tree = (CC_TREE*)malloc(sizeof(CC_TREE));
Tree->LChild = NULL;
Tree->RChild = NULL;
Tree->Value = Value;
return Tree;
}
if (Value <= Tree->Value)
{
Tree->LChild = InsertNewNode(Tree->LChild, Value);
}
else if (Value >= Tree->Value)
{
Tree->RChild = InsertNewNode(Tree->RChild, Value);
}
return Tree;
}
int TreeInsert(CC_TREE *Tree, int Value)
{
CC_UNREFERENCED_PARAMETER(Tree);
CC_UNREFERENCED_PARAMETER(Value);
Tree = InsertNewNode(Tree, Value);
return 0;
}
I try and construct the tree in my main function:
int retVal = -1;
CC_TREE* usedTree = NULL;
retVal = TreeCreate(&usedTree);
if (0 != retVal)
{
printf("TreeCreate failed!\n");
goto cleanup;
}
retVal = TreeInsert(usedTree, 20);
if (0 != retVal)
{
printf("TreeInsert failed!\n");
}
but for some reason the usedTree remains null. I know that I should use CC_TREE** Tree in the insert function, but I am not allowed to.

The insert function in the header file looks like this:
int TreeInsert(CC_TREE *Tree, int Value);
If you cannot change the function signature or (ew!) use a global variable to return the root pointer to the caller, then your best alternative is probably to use a dummy tree root. That would look something like this:
int TreeInsert(CC_TREE *Tree, int Value) {
// Tree points to a dummy root node containing no data.
// Tree->LChild is the actual root pointer
CC_TREE *root = Tree->LChild;
int status = 0;
// ... perform insertion, possibly resulting in a different value for the
// root pointer ...
Tree->LChild = root;
return status;
}
That assumes that the first argument to TreeInsert() is always a valid pointer to a CC_TREE. If you do this, then all other tree functions should work analogously.
You would use that from main() like so:
int retVal;
CC_TREE dummy_tree_root = { 0 };
retVal = TreeInsert(&dummy_tree_root, 42);
Note that this approach in effect uses a double pointer via an indirect route (no pun intended). A CC_TREE * is not itself a double pointer, but there are still two levels of indirection between that pointer and either the left or the right child of the node to which it points.
Note also that a cleaner way of doing this would involve providing a wrapper structure representing the overall tree instead of using a bare tree node or tree node pointer for the purpose. The data structures would be something like this:
struct node {
int value;
struct node *left;
struct node *right;
};
struct tree {
struct node *root;
// optionally other data, such as size, height, etc.
};

Related

Omitting ampersand in function call

I'm trying to implement ADT binary tree in C and I would like use API, which functions has form like foo(object, value). As far I wrote working tree for int value, but when I call BinTree_insert function I have to use operator"&" to get address of object. Is it possible to modify this function to omit & ?
typedef struct __bintree_node_t
{
int data;
struct __bintree_node_t* left;
struct __bintree_node_t* right;
}bintree_node_t;
static void __BinTree_insert(bintree_node_t** node, int value)
{
if(!(*node))
{
*node = __BinTree_newNode();
(*node)->data = value;
}
else if((*node)->data < value)
__BinTree_insert(&(*node)->left, value);
else if((*node)->data > value)
__BinTree_insert(&(*node)->right, value);
}
void BinTree_insert(bintree_node_t* node, int value)
{
//??????
}
int main(void)
{
bintree_node_t* root = 0;
BinTree_insert(root, 2); //sth like this
__BinTree_insert(&root, 1); //instead of this
}
You have the following options:
Instead of modifying the passed pointer to a pointer, you could return a new pointer instead. But that means using the returned value, which defeats the encapsulation a bit:
static void BinTree_insert(bintree_node_t* node, int value)
{
if (!node)
{
node = __BinTree_newNode();
node->data = value;
}
else if (node->data < value)
node->left = __BinTree_insert(node->left, value);
else if (node->data > value)
node->right = __BinTree_insert(node->right, value);
}
int main(void)
{
bintree_node_t* root = 0;
root = BinTree_insert(root, 2);
}
Or if you just want to change the initial call, you could maintain the pointer-to-pointer yourself:
int main(void)
{
bintree_node_t* root = 0;
bintree_node_t** rootPtr = 0;
__BinTree_insert(rootPtr, 2);
}
Or you could define a type which further encapsulates the pointer, but that adds quite a bit more code and memory allocation.
Not sure what the whole point is, though?
You've implemented your insert() function so that it modifies its first parameter. To do that, you have to pass the root by pointer; if you passed it by value (a bintree_node_t*), a change of the root inside BinTree_insert() would not be reflected outside the function (though changes to the root node would be).
For example, if the tree is empty (root equals NULL), your insertion function creates a new node, and has the root pointer point at that node; that can't be done if you want to keep the original root pointer, which would continue being NULL.
What you could do is have the insertion function return the new root. Then you could pass the old root as a bintree_node_t* (i.e. by value).

Make function pointers members of structures in c

I am completely noob when I work with C. Very weak with pointers.
I have written a struct for a binary search tree. But when I try to access it from code it throws an error:
Process terminating with default action of signal 11 (SIGSEGV).
Bad permissions for mapped region at address 0x0`.
Here is my struct (in bst.h):
typedef struct tree Tree;
typedef struct tree{
Node * root;
Data * (*insert)(Tree * bst, Data value); //i get error in main when I make a call
Data * (*search)(Tree * bst, Data value);
void (*sort)(Tree *, Data *);
int (*compare)(Tree *t, Tree * copy);
Tree * (*clone)(Tree *t);
void (*delete)(Tree *bst);
void (*removeData)(Tree * bst, Data value);
}Tree;
Member functions (in bst.c):
Node * newNode(Data data, Node * parent) {
printf("inside new node\n");
Node * node = malloc(sizeof(Node));
if(parent!=NULL) {
if((parent->data.value)> data.value) {
parent->left=node;
}
else {
parent->right=node;
}
}
node->parent=parent;
node->left=NULL;
node->right=NULL;
node->data=data;
printf("after inside newNode\n");
return node;
}
Tree * newTree() {
Tree *tree;
tree = (Tree*)malloc(sizeof(Tree));
tree->root=NULL;
return tree;
}
// not getting inside in this function
Data * insert(Tree * tree, Data data) {
if(tree->root==NULL) {
tree->root = newNode(data,NULL);
} else{
return insertNode(tree->root,data);
}
return NULL;
}
Here is my main() that calls this function (in main.c):
Tree *bst = newTree();
assert(bst->root == NULL);
printf("1.");
for (i = 0; i < num_data; i++){
bst->insert(bst, (Data){d[i]});
printf("inside for loop");
}
I am not sure whether this is the right way to make function pointers as members of struct.
In newTree(), you are not assigning your functions to the function-pointers inside of the allocated tree struct.
Data* insert(Tree* tree, Data data);
// other function declarations as needed...
Tree* newTree() {
Tree *tree = (Tree*) malloc(sizeof(Tree));
if (!tree) return NULL;
tree->root = NULL;
tree->insert = &insert; // <-- ADD THIS!
// and do the same for your other function pointers...
tree->search = ...;
tree->sort = ...;
tree->compare = ...;
tree->clone = ...;
tree->delete = ...;
tree->removeData = ...;
return tree;
}

Generic Function Of Stuct Declaration

I have built a generic Binary Search Tree.
typedef struct Tree {
void* data;
struct Tree *left;
struct Tree *right;
}Tree;
And two functions that create a Tree with different data type variables.
Tree* GetNewTreeInt(){
Tree* newTree = (Tree*)malloc(sizeof(Tree));
*((int*)newTree->data);
newTree->left = newTree->right = NULL;
return newTree;
}
Tree* GetNewTreeChar(){
Tree* newTree = (Tree*)malloc(sizeof(Tree));
*((char*)newTree->data);
newTree->left = newTree->right = NULL;
return newTree;
}
I have tried to create a generic function that store the function by address
Tree* CreateTree();
int main() {
void* root;
scanf("%d", &choose);
if(choose==0){
Tree* CreateTree=GetNewTreeInt();
(Tree*)root=CreateTree();
}
But I keep getting the following error: called object type "Tree*" (aka 'struct Tree*') is not a function or function pointer
This:
Tree* CreateTree();
..declares a function CreateTree that returns a Tree*, without fully defining the function (no function body, just a prototype). Whereas this:
Tree* CreateTree=GetNewTreeInt();
declares a variable of type Tree* named CreateTree, and calls the GetNewTreeInt() function assigning its return value to CreateTree. This gives you your error since you've already declared a function with the same name.
If you want CreateTree to be a function pointer, and to point it at the GetNewTreeInt function, you need to declare it as (either globally or within main, not both):
Tree *(*CreateTree)();
..and then point it at GetNewTreeInt like this:
CreateTree = GetNewTreeInt;
..and then you can call the function through the pointer with just CreateTree() as with a normal function, eg.:
root = CreateTree();
If you want a typedef of the function pointer type, you can do that as follows:
typedef Tree *(*CreateTreeFuncType)();
...and declare CreateTree as:
CreateTreeFuncType CreateTree;
instead of using the function pointer syntax mentioned earlier.
It looks like you were trying to use a function pointer. To do that you would need to declare a function pointer to a function which return a Tree*, not a Tree* directly:
if(choose==0) {
Tree* (*CreateTree)(void);
CreateTree = &GetNewTreeInt;
}
However, your two functions are identical, since the line *((int*)newTree->data); has no side-effects. You could just create a function like this instead:
Tree* GetNewTreeInt(void){
Tree* newTree = (Tree*)malloc(sizeof(Tree));
newTree->left = newTree->right = NULL;
return newTree;
}
It's when you access tree->data that you need to cast the void * to a pointer of the type you know it contains. If you don't know what type of tree you have externally, you should add another field to your struct which signifies which type of data is stored. If you're only storing small data types like int and char I would recommend using a union instead of a void pointer, since a union will store the data inside the Tree in memory. Either way you'll still need something in your tree to indicate what type of data its storing.
typedef struct Tree {
// 0 means there is an int in tree->data.i,
// 1 means there is a char in tree->data.c
int type;
union {
int i;
char c;
} data;
struct Tree *left;
struct Tree *right;
} Tree;
Then your two functions become:
Tree* GetNewTreeInt(void){
Tree* newTree = (Tree*)malloc(sizeof(Tree));
newTree->type = 0;
newTree->data.i = 0; // Set an initial value
newTree->left = newTree->right = NULL;
return newTree;
}
Tree* GetNewTreeChar(void){
Tree* newTree = (Tree*)malloc(sizeof(Tree));
newTree->type = 1;
newTree->data.c = '\0'; // Set an initial value
newTree->left = newTree->right = NULL;
return newTree;
}
And you can use a function pointer just like this:
if(choose==0) {
Tree* (*CreateTree)(void);
CreateTree = &GetNewTreeInt;
Tree* tree = CreateTree();
tree->data.i = 7;
}
Each tree will have either a data.i or data.c, but not both, later when you're traversing your trees you can check their type to find out which:
if ( tree->type == 0 ) {
int data = tree->data.i;
} else if ( tree->type == 1 ) {
char data = tree->data.c;
}
EDIT
If you really want to use a void *, you can still add the int type to your struct, and when traversing you could do something like this:
if ( tree->type == 0 ) {
int data = *(int *)tree->data;
} else if ( tree->type == 1 ) {
char data = *(char *)tree->data;
}

insertion binary search tree in C

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(){}
}

binary search tree pointer problem

I tried to implement a binary search tree for the purpose of (re-)learning C. The problem is that the this current = new; does not work as desired because the tree.root is still a null pointer after adding two nodes. What's wrong with that?
#include <stdlib.h>
#include <stdio.h>
typedef struct BinaryNode {
int key;
double value;
struct BinaryNode *left;
struct BinaryNode *right;
} BinaryNode;
typedef struct BinaryTree {
struct BinaryNode *root;
} BinaryTree;
static void binary_tree_insert_recursive(BinaryNode *current, BinaryNode *new) {
if (current == NULL || current->key == new->key) {
current = new;
} else if (current->key > new->key) {
binary_tree_insert_recursive(current->left, new);
} else if (current->key < new->key) {
binary_tree_insert_recursive(current->right, new);
}
}
void binary_tree_insert(BinaryTree *tree, int key, double value) {
BinaryNode *new = (BinaryNode *) malloc(sizeof(BinaryNode));
new->key = key;
new->value = value;
binary_tree_insert_recursive(tree->root, new);
}
int main(void) {
BinaryTree tree;
binary_tree_insert(&tree, 5, 123);
binary_tree_insert(&tree, 10, 123);
printf("%p\n", tree.root);
return 0;
}
Thank you!
I believe the problem with current = new; is that you are changing your local copy of current. After the function is done, this modification is not visible.
I suspect you want something like:
static void binary_tree_insert_recursive(BinaryNode **current, BinaryNode **new)
{
if (*current == NULL || (*current)->key == (*new)->key) {
*current = *new;
/* ... */
Well explained in the C FAQ.
current is a pointer to a node. When you pass it to binary_tree_insert_recursive from binary_tree_insert the value of the pointer is passed. So although it is changed inside the called function, the change is not reflected in the calling function. You need to modify the function to take the address of the pointer you wish to change:
static void binary_tree_insert_recursive(BinaryNode **current, BinaryNode *new)
{
if (*current == NULL || (*current)->key == new->key) {
*current = new;
all that current = new does is make it so that the variable current points at the thing that new is pointing at. No copying takes place, and the function has no effect on that codepath.
new is a keyword. Choose a different variable name.

Resources