I'm currently implementing a Binary Search Tree and I'm trying to find the smallest value in the tree with a function like this:
int smallest(Tr *T, void *Item) {
TNode * n;
if(Size(T) == 0)
return 0;
while(n->left != NULL) {
n = n->left;
}
return 1;
}
Where I have the structs:
typedef struct TNodeTag {
void *v;
struct TNodeTag*left, *right, *parent;
} TNode;
typedef struct {
TNode *root;
TNode *current;
void * (*copyItems) (void *, void *);
int value;
} Tr;
And at first a initialize function:
void Initialize (Tr *T,void * (*copyItems) (void *, void *),{
T->root = NULL;
T->copyItems = copyItems;
T->value = 0;
}
Where void * Item is the address of where a copy of the smallest node should be stored (using the copyValue function)(Which I'm not sure how to create) . Tr * T is a pointer to the first struct. The function smallest, is so posed to return 1 if it can find a smallest value, 0 otherwise (tree is empty).
I'm not sure if my implementation of finding the smallest node is correct, since my function will always return 1,unless the tree is empty?
If I understand correctly, the function "smallest" must return 1 if there exists a smallest value in the tree and 0 otherwise. That doesn't sound very useful, since there will always be a smallest value in the tree, so long as the tree is not empty. In this regard, your function is correct.
However, your function tries to de-reference the pointer n before it is being assigned to anything, in the while loop. All bets are off as to what will actually happen and this is probably not something you want. (I imagine the compiler is optimizing this away since n is never used.) I think what you're trying to do is find the smallest value, in which case, you should first assign the address of root node of the tree to n. You could do
...
n = T->root;
while(n->left != NULL) {
n = n->left;
}
so that, after the loop, n will point to the node with the smallest value.
Hope this helps :)
Related
I'm working on implementing a binary search tree data structure in C, but I got stuck at the part where you point to the left or right child. I understand that if the value you're inserting is smaller than the root, it goes to the left and to the right if it's larger. I'm just struggling with the double pointers part as shown in the code below. Let's take bs_tree_insert_left for example, I want pos->left_child to point to the left_child in order to place the value given there, but I'm not sure how I would write this.
For context regarding the main function, the numbers in arr[] will be randomly shuffled but I removed that part of the code to keep the post short and compact.
struct node
{
int value;
struct node *left_child;
struct node *right_child;
};
typedef struct node BSTree;
typedef struct node* BSTreePos;
BSTree *bs_tree_make(int value){
// Allocate memory for new node
struct node* origin = (struct node*)malloc(sizeof(struct node));
// Assign data to this node
origin->value = value;
// Initialize left and
// right children as NULL
origin->left_child = NULL;
origin->right_child = NULL;
return (origin);
}
BSTreePos bs_tree_insert_left(int value, BSTreePos pos){
pos->left_child = bs_tree_make(value);
return pos->left_child;
}
void insert_value(int value, BSTreePos pos)
{
if (pos == NULL) return bs_tree_make(value);
if (value < pos->value)
{
pos->left_child = bs_tree_insert_left(value, pos->left_child);
}
else if (value > pos->value)
{
pos->right_child = bs_tree_insert_right(value, pos->right_child);
}
}
int main(void)
{
// Create an array with the values 1, 2, ..., 10 and print out the content.
int n = 10;
int arr[n];
for (int i = 0 ; i < n ; i++) {
arr[i] = i + 1;
}
print_array(n, arr);
BSTree *tree = bs_tree_make(arr[0]);
for (int i = 1 ; i < n ; i++) {
BSTreePos pos = bs_tree_root(tree);
insert_value(arr[i], pos);
}
return 0;
}
You know what, I'm just going to write the correct algorithm that uses the double pointer to maximum effect.
void insert_value(int value, struct node **node)
{
if (*node == NULL) {
*node = malloc(sizeof(struct node));
node[0]->value = value;
node[0]->left_child = NULL;
node[0]->right_child = NULL;
} else if (node[0]->value < value)
insert_value(value, &node[0]->left_child);
else if (node[0]-> value > value)
insert_value(value, &node[0]->right_child);
/* else duplicate value found -- don't insert (from OP's code) */
}
BSTree *tree = NULL;
for (int i = 0 ; i < n ; i++) {
insert_value(arr[i], &tree);
}
node[0]->value is the idiomatic way of accessing a struct through a double pointer.
But let's look at how this works and how much value this gets out of the double pointer. The empty tree is stored as the NULL pointer. This makes initializing the tree and adding a node to the tree the same code. Notice how insert_value takes a double pointer to the tree; this allows it to fill out the root node when adding the first node, or any child node thereof. Thus double pointer which is pointer to pointer is used to update a pointer to a node when we make a new one.
With this algorithm, having a bs_tree_insert_left literally makes no sense. The whole idea is the code that does the insertion doesn't know where it is inserting the node.
Fun fact: the compiler will transform away the recursion for us when compiling with optimizations.
This question already has answers here:
Changing address contained by pointer using function
(5 answers)
Closed 1 year ago.
I am trying to add a node to a binary search tree (BST). My adding method code is as follows:
int add(node_t* n, node_t* tn){
if(tn == NULL){tn = n;}
if(n->value < tn->value){add(n, tn->leftNode);}
else if (n->value > tn->value){add(n, tn->rightNode);}
else{return 0;}
return 1;
}
The method is called in main for BST t1 and node n1: add(n1, t1->root). The return value of the function is a 0 or 1, 0 if another node of the same value exists in the tree- in which case the new node is not added- and 1 if the node is successfully added. Struct tree_t's count variable is updated in the main function as follows: t1->count += add(n1, t1->root).
However, after I call the add function, the tree t1 still seems to be empty. My only guess is that add is adding a node to a copy of t1 which is being destroyed after the function call, but I don't understand why this is the case as it is passed in as a pointer.
The structs tree_t and node_t are attached below:
typedef struct node{
int value;
struct node* leftNode;
struct node* rightNode;
} node_t;
typedef struct tree{
struct node* root;
int count;
} tree_t;
And here is my main method:
int main(){
tree_t t1;
tree_init(&t1);
node_t n1;
node_init(&n1, 5);
node_t n2;
node_init(&n2, 7);
t1.count += add(&n1, t1.root);
t1.count += add(&n2, t1.root);
print_tree(t1.root); //this prints nothing, and I'm confident that print_tree works
}
Any help is greatly appreciated!
If you pass to function pointer to type, you can change the variable that pointer points to. But you can't change the address, that this pointer points to (can't change pointer itself).
If you want to change pointer itself (address that he points to), you need to pass in your function pointer to pointer:
int add(node_t *n, node_t **tn){
if(*tn == NULL){*tn = n;}
if(n->value < *tn->value){add(n, *tn->leftNode);}
else if (n->value > *tn->value){add(n, *tn->rightNode);}
else{return 0;}
return 1;
}
Hello im trying to make a program that takes a linked list of integers and sums the squares of the int, using recursion. I have tried this so far, however i cant get the function of summin the squares to work. I dont know if using the pow() is the best way?
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include<math.h>
typedef struct node
{
int value;
struct node* next;
} node;
/* terminal node at the end of the list */
node SENTINEL = {0, 0};
/* utility functions to create and free lists */
node * make_node(int v, node * q)
{
node* p = (node*) malloc(sizeof(node));
p->value = v;
p->next = q;
return p;
}
int sum_squares(node* list)
{
if(list == 0)
return 0;
else
{
return(pow(&list, 2) + sum_squares(list));
}
}
void free_node(node* p)
{
if(p == &SENTINEL)
return;
else
{
free_node(p->next);
free(p);
}
}
int main(void)
{
int sum;
node* list =
make_node(1,
make_node(2,
make_node(3,
make_node(4,
make_node(5, &SENTINEL)
)
)
)
);
sum = sum_squares(list);
printf("The sum of squares is: %d\n",sum);
free_node(list);
return 0;
}
it should equal 55 with the current numbers
There are a few things that you should edit!
In your sum_squares function, your base case checks whether current node list is equal to 0, but you should check whether it's the sentinel node.
In the recursive case, you should use pow(&list, 2). &list, however, returns the address of the argument list. What you're looking for is the integer value held in the node struct, which you get by using the -> operator. &list becomes list->value.
Finally, when you recursively call your next function, you pass it the same node. This will cause it to infinitely call itself on the same node, and never actually step through the list. Instead of just passing list again, you should pass list->next!
The changes are applied below:
int sum_squares(node* list)
{
if (list == &SENTINEL)
return 0;
return (pow(list->value, 2) + sum_squares(list->next));
}
I have this homework where I have to convert a min-heap represented in array:
DEFINE #SIZE
typedef int Heap[SIZE]
and implement it in a tree like so:
typedef struct node{
int val;
struct no *left, *right;
} Node, *Tree;
and as a reminder the index of min-heaps arrays is as follows:
#DEFINE PARENT(i) (i-1)/2
#DEFINE LEFT(i) 2*i + 1
#DEFINE RIGHT(i) 2*i + 2
so, how do I do this?
I started on something like this:
Tree heapToTree(int * heap){
Tree *t = malloc(sizeof(struct node));
t->val = heap[0];
Tree *aux = t; //save initial tree position
for(i=0;i<SIZE;i++){
aux->left=malloc(sizeof(struct Node));
aux->left->val=heap[i*2 +1];
aux->right=malloc(sizeof(struct Node));
aux->right->val=heap[i*2 +2];
}
Am I on the right path? I think this should be done recursively, but how?
thanks in advance
There is one thing that you are lacking is - not making the newly created node's links (left and right) to the NULL initially. No matter what, any kind of tree implementation this is very useful - helps in traversal, finding an element (which is again a traversal) etc.
Also in the loop you didn't change the value of aux (or atleast you didn't show) - as a result you are writing over the old values and having memory leak.
Apart from that not checking the return value of malloc is another point. You should check the return value of malloc - if NULL then you should handle that distinctly (error handling) from that of usual code flow.
Considering that heap is implemented in an array (0-index) you can do this to convert it to tree.
struct node *convIntoTree(int pos,int sz, int *heap){
if(pos >= sz ) return NULL;
struct node* root = malloc(sizeof *root);
if( root == NULL ){
perror("Malloc failed");
exit(EXIT_FAILURE);
}
root->data = heap[pos];
root->left = convIntoTree(pos*2+1,sz);
root->right = convIntoTree(pos*2+2,sz);
return root;
}
Call it like this
struct node *root = convToTree(0,heapsize,heap);
The solution is simply applying a brute force method of traversing every node of the heap and then allocate memory for it and populate it's left and right child recursively.
in my assignment i have to create a binary tree where the user inputs the details.
the first thing the user does is enter 1 if they want to create a number tree or 2 if they want a word tree.
the type of tree they pick is the type it will be for the duration of the running of the program.
there are many functions (and a few structs) that must be written in order to complete the assignment.
my question is how can i write general functions that will work for both int and char?
for example if it is a number tree then the struct for node would include:
int key;
list_t* valueslist;
node* left;
node* right;
but if it was a word list than the struct would look the same except instead of int key it would be char key.
thanks in advance for any help!
The way you may go about it, is to define that data in the struct as a union like so:
struct _Node
{
...
union
{
char* c;
int i;
} data;
};
Than when user makes the choice, access the correct union member according to it.
EDIT
So, let's say the user picked a type, int for instance. And you wish to insert a new value into the tree. (I'll omit error checking fro brevity, but remember to check memory allocation succeeded).
struct _Node* newElem = allocNode();
if (get_user_elected_type() == INT)
newElem->data.i = user_input.i; // Your methods will also need to accept a union
This way has it's serious drawbacks (it's not easy to add a new type, for instance). And most of all it demonstrates how yucky generic programming can be in C. (Using void* can get just as yucky eventually).
There are few solutions to resolve this problem (what you are trying to do is called generic programming)
Use void * key, and fill it with the right data (this is
recommended, because is more generic, but it is also more complicated)
Use a union with 2 fields: an int and a char*
For a homework assignment, the simpler approach will be to use a union type for your data:
struct node {
union {
char *s
int i;
} data;
struct node *left;
struct node *right;
};
and create two sets of functions, one to manage integer values and the other to manage string values:
void insertIntNode(struct node *root, struct node *newNode)
{
if (newNode->data.i < root->data.i)
if (root->left != NULL)
insertIntNode(root->left, newNode);
else
root->left = newNode;
else
if (root->right != NULL)
insertIntNode(root->right, newNode);
else
root->right = newNode;
}
void insertWordNode(struct node *root, struct node *newNode)
{
if (strcmp(root->data.s, newNode->data.s) < 0)
if (root->left != NULL)
insertWordNode(root->left, newNode);
else
root->left = newNode;
else
if (root->right != NULL)
insertWordNode(root->right, newNode);
else
root->right = newNode;
}
bearing in mind you'll need to do some additional memory management for word data:
struct node *createWordNode(char *str)
{
struct node *r = malloc(sizeof *r);
if (r)
{
r->data.s = malloc(strlen(str) + 1);
if (r->s)
strcpy(r->data.s, str);
r->left = r->right = NULL;
}
return r;
}
void destroyWordNode(struct node **n)
{
free((*n)->data.s);
free(*n);
*n = NULL;
}
A more flexible approach is to use a void * to point to your data item, and then delegate all type-aware operations (allocation, assignment, comparison, display, etc.) to other functions which are hidden behind a set of function pointers. For example:
struct node {
void *data;
struct node *left;
struct node *right;
};
struct node *newNode(void *data, void *(*copy)(const void *))
{
struct node *n = malloc(sizeof *n);
if (n)
{
n->left = n->right = NULL;
n->data = copy(data);
}
return n;
}
void insert(struct node *root, struct node *newNode,
int (*compare)(const void *, const void *))
{
if (compare(newNode->data, root->data) < 0)
if (root->left != NULL)
insert(root->left, newNode, compare);
else
root->left = newNode;
else
if (root->right != NULL)
insert(root->right, newNode);
else
root->right = newNode;
}
In the examples above, the details of allocating memory for a node's data element and comparing two data elements are delegated to other functions, and pointers to those functions are passed as parameters to the list management functions. This way you wind up writing a single newNode and insert function, but one that's capable of handling arbitrary node data types. So, for your integer tree, you'd write functions like
void *copyInt(const void *data)
{
const int *src = data;
int *dst = malloc(sizeof *dst);
if (dst)
{
*dst = *src;
}
return dst;
}
int compareInt(const void *lhs, const void *rhs)
{
const int *ilhs = lhs;
const int *irhs = rhs;
if (*ilhs < *irhs)
return -1;
else if (*ilhs == *irhs)
return 0;
else
return 1;
}
then you'd call newNode and insert like
void insertIntValue(struct node *root, int value)
{
struct node *n = newNode(&value, copyInt);
if (n)
insert(root, n, compareInt);
}
The big disadvantage of this approach is that you throw type safety right out the window and into oncoming traffic; because we're using void * for everything. the compiler won't be able to catch type mismatches for us. There's nothing to stop you from passing the wrong copy or comparison function to the generic routines for a particular type.
Which brings us to our second disadvantage - you still need to write a type-aware interface (such as the insertIntValue function above) for each data type you want to support (insertFloatValue, insertStringValue, insertMyObnoxiousDataTypeValue, etc.) along with all of the delegates. Partly to avoid type-safety issues, and partly because our "generic" functions really aren't designed to be called directly. For example, the newNode function expects a pointer as the first parameter, meaning you can't write something like
struct node *n = newNode(10, copyInt);
or
struct node *n = newNode(3.14159, copyDouble);
IOW, you can't pass a literal as the first argument; you must pass the address of an object.
The third main disadvantage is you wind up doing a lot of memory management, which is a pain. You have to create copies of your inputs; otherwise, you wind up assigning the same pointer value (the one passed to newNode) to every node in your tree. Every malloc must have a matching free or you will wind up leaking a lot of memory. You have to be disciplined in how you allocate and deallocate your data items.
Building robust generic containers in C is, frankly, a massive pain in the ass. The only real reason to do it is so you can truly appreciate the value of templates in C++ and generics in Java and C#.