multiway tree memory allocation of children - c

I am trying to build a multi-way tree in C. I've got stuck on allocation memory for childrens.
I have a vector which contains the fathers of each node. Here is my code:
#define MAX_CHILDS 10
int t[10] = {1, 2, 4, 1, -1, 3, 2, 1, 0, 4};
NODE *root;
NODE *v[MAX_CHILDS];
//add children for specified node
void ADD_REF(int i) {
v[i]->children[v[i]->child_count] = v[t[i]];
v[i]->child_count++;
}
//creates the tree
NODE *T1(int n, int *t) {
int root = 0;
for (int i = 0; i < n; i++) {
v[i] = (NODE *) malloc(sizeof(NODE));
v[i]->info = i;
v[i]->child_count = 0;
v[i]->children = (NODE **) malloc(sizeof(NODE)); // I think the problem is here
}
for (int i = 0; i<n; i++) {
if (t[i] == -1)
root = i;
else
ADD_REF(i);
}
return v[root];
}
void main() {
root = T1(MAX_CHILDS, t);
print_tree(root, 0); // prints the tree
}
Here is the structure of the NODE:
typedef struct NODE {
int info;
int child_count;
struct NODE **children;
} NODE;
I am not sure exactly if the problem is at the memory allocation. With my logic it should work.

I've found my error.
The memory allocation was ok. The problem was at adding new children.
I've added children for the current node instead of adding children to it's parent.
This was the solve:
void ADD_REF(int i) {
v[t[i]]->children[v[t[i]]->child_count] = v[i];
v[t[i]]->child_count++;
}

Related

convert array to binary tree with recursive strategy

I need to create a binary tree starting from vector containing some zeros where a zero represents a node that doesn't exists. for example if I got:
int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,5};
I would like my output like this:
10
/ \
4 7
/ \ \
2 3 8
/ / \ /
9 2 4 5
my struct:
typedef struct node {
int n;
struct node * dx;
struct node * sx;
} *Bit_node;
method to build one node:
Bit_node bit_new(int n) {
Bit_node new_node = malloc(sizeof(struct node));
new_node -> n = n;
return new_node;
}
method to build the whole tree:
Bit_node bit_arr2tree(int a[], int size, int i) {
if (i>= size) {
return NULL;
}
if(a[i] != -1) {
Bit_node new_node = bit_new(a[i]);
new_node -> sx = bit_arr2tree(a, size, i*2 +1);
new_node -> dx = bit_arr2tree(a, size, i*2 +2);
}
return new_node;
}
But with my implementation my tree is built not considering the "holes". Is there a way to considering them , keeping the recursive strategy?
First of all, int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,5}; shouldn't produce the tree you expect, with 5 as the left child of 8. Since 8 is at index 6, its left child would be at index 6 * 2 + 1 == 13. So your input should probably be int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,-1,-1,5};, with two extra -1s towards the end of the array to push 5 to the correct index.
Your implementation can't work because in the pattern:
{
Bit_node new_node = malloc(...)
}
return new_node;
new_node is being accessed when not in scope. If you encounter a -1, you want to return NULL just like you're doing if you go out of bounds on the array. Returning NULL says "there is no child here", which is exactly what you want to communicate to a parent frame so that it sets the missing child to NULL.
The fix should be pretty straightforward:
Bit_node bit_arr2tree(int a[], int size, int i) {
if (i>= size || a[i] < 0) {
// ^^^^^^^^^^^
return NULL;
}
Bit_node new_node = bit_new(a[i]);
new_node->sx = bit_arr2tree(a, size, i * 2 + 1);
new_node->dx = bit_arr2tree(a, size, i * 2 + 2);
return new_node;
}
As an aside, I'd caution against typedeffing away pointers. This makes the code less readable and hides information.
Here's a runnable proof of concept:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *left;
struct Node *right;
};
struct Node *arr2tree(int arr_len, int *arr, int i) {
if (i >= arr_len || arr[i] < 0) {
return NULL;
}
struct Node *node = malloc(sizeof(*node));
node->data = arr[i];
node->left = arr2tree(arr_len, arr, i * 2 + 1);
node->right = arr2tree(arr_len, arr, i * 2 + 2);
return node;
}
void print_tree(struct Node *root, int depth) {
if (root) {
print_tree(root->right, depth + 4);
for (int i = 0; i < depth; i++) {
printf(" ");
}
printf("%d\n", root->data);
print_tree(root->left, depth + 4);
}
}
void free_tree(struct Node *root) {
if (root) {
free_tree(root->left);
free_tree(root->right);
free(root);
}
}
int main() {
int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,-1,-1,5};
struct Node *root = arr2tree(sizeof(a) / sizeof(a[0]), a, 0);
print_tree(root, 0);
free_tree(root);
return 0;
}
Output:
8
5
7
10
4
3
2
4
2
9
Given that the input data structure does not guarantee the relationship between parent and children is i*2+1 and i*2+2, a recursive solution is not really called for. The input sequence represents a breadth-first order, so it would be more natural to build the tree in breadth-first order.
As a side note: the function bit_new should also initialise the sx and dx members: you don't want to leave those with undefined values.
Here is how you could write your algorithm:
Bit_node bit_new(int n) {
Bit_node new_node = malloc(sizeof(struct node));
new_node -> n = n;
new_node -> sx = NULL;
new_node -> dx = NULL;
return new_node;
}
Bit_node bit_arr2tree(int a[], int size) {
if (size == 0) {
return NULL;
}
// Create a temporary array to store the node pointers
Bit_node nodes[size];
// Create the nodes
for (int i = 0; i < size; i++) {
nodes[i] = a[i] == -1 ? NULL : bit_new(a[i]);
}
// To link the nodes, use two indexes: parent and child
for (int child = 1, parent = 0; child < size; child += 2, parent++) {
// Here we "skip the gaps": a parent cannot be NULL:
while (nodes[parent] == NULL) {
parent++;
}
nodes[parent] -> sx = nodes[child];
if (child + 1 < size) {
nodes[parent] -> dx = nodes[child + 1];
}
}
return nodes[0];
}

Node structure gains itself as a parent during expansion

My assignment is to write a solver for 3x3 sliding tile puzzle which has to embedded later.
I have the structure
struct node
{
char state[9];
struct node* parentNode;
char lastMove;
} node;
I use a pseudo stack for
struct node
{
char state[9];
struct node* parentNode;
char lastMove;
} node;
I use a stack which will be used later for the IDS algorithm.
struct node stack[60000];
struct node* Node = stack;
#define push(Node, n) (*((Node)++) = (n))
#define pop(Node) (*--(Node))
My function expandNode creates all valid child nodes of its given parent
void expandNode(struct node* parent)
{
char help;
int emptyField = -1;
struct node newNode;
for (int i = 0; i < 9; i++)
{
if (parent->state[i] == '0') emptyField = i;
}
for (int i = 0; i < 4; i++)
{
if(lastMoveVal(parent->lastMove, moves[i]) == '0') continue;
if (moveValid(parent->state, moves[i]) == '1')
{
newNode.parentNode = parent;
...
My main function
void main()
{
struct node root;
char rootState[9] = { '6','8','3','0','4','5','1','7','2' };
assignArray(root.state, rootState);
push(Node, root);
struct node curr;
curr = pop(Node);
expandNode(&curr);
for(int i = 0; i < 10; i++)
{
curr = pop(Node);
printf("\n");
for(int j = 0; j<9; j++)
{
printf("%c", curr.state[j]);
};
printf(" PARENT: ");
for(int j = 0; j<9; j++)
{
printf("%c", curr.parentNode->state[j]);
};
}
}
Here is the output:
683405172 PARENT: 683405172
683145072 PARENT: 683145072
083645172 PARENT: 083645172
As you see the expansion of the nodes is correct but the state of the parent node is not the expected 683045172 but the state of node itself.

AVL Tree unit test, get the height of nodes without parents

For my school assignment I have to implement an AVL tree node insertion. I have this unit test, with 4 tests, and 2 of them always fails.
I use two global variables, one Array to store the numbers and one integer for the index.
int pom = 0;
int test_output[1000];
The first 2 test checks the rotations with parents:
void test_right_rotation_with_parent() {
//Arrange
struct Node* root = NULL;
int insert_nodes[] = { 15,10,5 };
int correct_output[] = { 10,2,5,1,15,1 }; // node -> key, node -> height;
char* passed = PASSED;
//Act
for (int i = 0; i < 3; i++) {
insert(root, insert_nodes[i]);
}
preOrder(root);
//Assert
for (int i = 0; i < 6; i++) {
if (correct_output[i] != test_output[i]) {
passed = FAILED;
break;
}
}
printf("%s: %s\n", __func__, passed);
}
Output: test_right_rotation_with_parent: PASSED.
Same test for left rotation. Then I have 2 test for rotations without parents. These are the test which I cannot pass.
void test_right_rotation_without_parent() {
//Arrange
struct Node* root = NULL;
int insert_nodes[] = { 20,25,15,10,5 };
int correct_output[] = { 20,3,10,2,5,1,15,1,25,1 }; // node -> key, node -> height;
char* passed = PASSED;
//Act
for (int i = 0; i < 5; i++) {
insert(root, insert_nodes[i]);
}
preOrder(root);
...
}
Output: test_right_rotation_without_parent: FAILED
PreOrder:
void preOrder(struct Node *root) {
if (root != NULL) { // this is the main problem if a node hasn't got parent
test_output[pom++] = root->key;
test_output[pom++] = root->height;
preOrder(root->link[0]); // left side
preOrder(root->link[1]); // right side
}
}
And this is the part of the insert function, which creates a Node, if previously there wasn't any.
struct Node *insert(struct Node *node, int key)
{
if (node == NULL)
{
struct Node *node = malloc(sizeof *node);
if (node != NULL)
{
/* if I do the same thing here which I did in preOrder,
* the sequence of the keys will be correct,
* however the height will always be 1 (for the without parent functions) */
node->key = key;
node->height = 1;
node->link[0] = node->link[1] = NULL;
}
return node;
}
else {...}
Is it possible to make this work with this method? Or I need to find another method if I want to pass these test?

realloc in recursion in trees

I am trying to find the maximum sum leaf to root path in a Binary Tree as in below
http://www.geeksforgeeks.org/find-the-maximum-sum-path-in-a-binary-tree/
1) I am unable to find why the path doesn't get printed in the main()
Is this because of wrong reallocs in the function.?
2) Also is my free correct?
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
/* A tree node structure */
struct node
{
int data;
struct node *left;
struct node *right;
};
// Returns the maximum sum and prints the nodes on max sum path
int maxsumtoleaf(struct node *node,int** path,int &height)
{
// base case
if (node == NULL)
return 0;
printf("\n At node %d,",node->data);
if (node->left==NULL && node->left==NULL) {
*path=(int*)realloc(*path,sizeof(int));
*path[0]=node->data;
height=1;
printf("\n value is %d,",*path[0]);
return node->data;
}
// find the target leaf and maximum sum
int rightheight=0,leftheight=0;
int *path1=NULL,*path2=NULL;
int left=maxsumtoleaf (node->left,&path1,leftheight);
int right=maxsumtoleaf (node->right,&path2,rightheight);
if ( left > right ) {
printf("\nbefore left is");
for(int i=0;i<leftheight;i++)
printf("%d,",path1[i]);
path1=(int*)realloc(path1,sizeof(int)*(leftheight+1));
if ( path1 == NULL ) {
printf("Out of Memory!\n");
return 0;
}
path1[leftheight]=node->data;
height=leftheight+1;
printf("\nafter left %d is ",leftheight);
for(int i=0;i<height;i++)
printf("%d,",path1[i]);
path=&path1;
return left+node->data;
} else {
printf("\nbefore right is");
for(int i=0;i<rightheight;i++)
printf("%d,",path2[i]);
path2=(int*)realloc(path2,sizeof(int)*(rightheight+1));
if ( path2 == NULL ) {
printf("Out of Memory!\n");
return 0;
}
path2[rightheight]=node->data;
height=rightheight+1;
printf("\nafter right is");
for(int i=0;i<height;i++)
printf("%d,",path2[i]);
path=&path2;
return right+node->data;
}
// return maximum sum
}
/* Utility function to create a new Binary Tree node */
struct node* newNode (int data)
{
struct node *temp = new struct node;
temp->data = data;
temp->left = NULL;
temp->right = NULL;
return temp;
}
/* Driver function to test above functions */
int main()
{
struct node *root = NULL;
/* Constructing tree given in the above figure */
/* (8<--2->-4)<-10->7 */
root = newNode(10);
root->left = newNode(-2);
root->right = newNode(7);
root->left->left = newNode(8);
root->left->right = newNode(-4);
int sum=0;
int** path=NULL;
int height=0;
sum = maxsumtoleaf(root,path,height);
printf ("\nSum of the nodes is %d ,len=%d", sum,height);
printf ("\nPath is ");
for(int i=0;i<height;i++)
printf("%d,",*path[i]);
free(path);
getchar();
return 0;
}
Output:
At node 10,
At node -2,
At node 8,
value is 8,
At node -4,
value is -4,
before left is8,
after left 1 is 8,-2,
At node 7,
value is 7,
before right is7,
after right is7,10,
Sum of the nodes is 17 ,len=2
Path is ---> Breaks at this point in main()
Code is C++ with passing args by reference and using new.
To make C, lots of little fixes including how C "reference" variable are passed (explicitly by address).
You are not doing rellloc() correctly should the allocation fail as you have lost the original pointer.
Always good form to NULL a pointer after freeing it.
#include <stdio.h>
#include <string.h>
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
/* A tree node structure */
struct node {
int data;
struct node *left;
struct node *right;
};
// Returns the maximum sum and prints the nodes on max sum path
int maxsumtoleaf(struct node *node, int** path, int *height) {
// base case
if (node == NULL)
return 0;
printf("\n At node %d,", node->data);
if (node->left == NULL && node->left == NULL) {
*path = (int*) realloc(*path, sizeof(int));
(*path)[0] = node->data;
*height = 1;
printf("\n value is %d,", *path[0]);
return node->data;
}
// find the target leaf and maximum sum
int rightheight = 0, leftheight = 0;
int *path1 = NULL, *path2 = NULL;
int left = maxsumtoleaf(node->left, &path1, &leftheight);
int right = maxsumtoleaf(node->right, &path2, &rightheight);
if (left > right) {
printf("\nbefore left is");
for (int i = 0; i < leftheight; i++)
printf("%d,", path1[i]);
path1 = (int*) realloc(path1, sizeof(int) * (leftheight + 1));
if (path1 == NULL) {
printf("Out of Memory!\n");
return 0;
}
path1[leftheight] = node->data;
*height = leftheight + 1;
printf("\nafter left %d is ", leftheight);
for (int i = 0; i < *height; i++)
printf("%d,", path1[i]);
*path = path1;
return left + node->data;
} else {
printf("\nbefore right is");
for (int i = 0; i < rightheight; i++)
printf("%d,", path2[i]);
path2 = (int*) realloc(path2, sizeof(int) * (rightheight + 1));
if (path2 == NULL) {
printf("Out of Memory!\n");
return 0;
}
path2[rightheight] = node->data;
*height = rightheight + 1;
printf("\nafter right is");
for (int i = 0; i < *height; i++)
printf("%d,", path2[i]);
*path = path2;
return right + node->data;
}
// return maximum sum
}
/* Utility function to create a new Binary Tree node */
struct node* newNode(int data) {
struct node *temp = malloc(sizeof *temp); // new struct node;
temp->data = data;
temp->left = NULL;
temp->right = NULL;
return temp;
}
/* Driver function to test above functions */
int main() {
struct node *root = NULL;
/* Constructing tree given in the above figure */
/* (8<--2->-4)<-10->7 */
root = newNode(10);
root->left = newNode(-2);
root->right = newNode(7);
root->left->left = newNode(8);
root->left->right = newNode(-4);
int sum = 0;
int* path = NULL;
int height = 0;
sum = maxsumtoleaf(root, &path, &height);
printf("\nSum of the nodes is %d ,len=%d", sum, height);
printf("\nPath is %p ", path);
// return 0;
for (int i = 0; i < height; i++)
printf("%d,", path[i]);
free(path);
path = NULL;
// getchar();
return 0;
}
Preferred realoc() use
// Somehow these are to be updated (initial to NULL and 0)
some_type *current_ptr;
size_t current_element_count; // best too use type size_t
size_t new_element_count = some_function(current_size);
void *new_ptr = realloc(current_ptr, new_element_count * sizeof *current_ptr);
if (new_ptr == NULL && new_element_count > 0) {
Handle_OOM(); // current_ptr is still same & current_element_count elements
return;
}
current_ptr = new_ptr;
current_element_count = new_element_count;
// continue on the happy path

Sequence insert at arbitrary index implemented with Linked list

I'm trying to implement sequence_insert_at using the add_to_front function here
Everything before
typedef struct sequence *Sequence;
is pasted from another c file.
void sequence_insert_at(Sequence s, int pos, int item)
{
struct node* temp = s->lst;
for(; pos > 0; --pos)
{
temp = temp->rest;
}
add_to_front(&temp, item);
++s->length;
if(!temp->rest)
{
s->end = temp;
}
//s->lst = temp;
}
I don't know why I keep getting a runtime error. if I clone s->lst and traverse the clone, I'm not modifying the pointer to the node in s, but if I change temp, s->lst should have the reflected changes since the nodes are all linked still. Any ideas as to how to fix this? I tried creating another node that is one before the temp after traversal, and then setting it->rest = temp, but that failed as well.
following mistakes a could spot but only so far to get the main function run
new_sequence does not initialize anything in Sequence it creates. lst is not initialized when you access it in sequence_insert_at
struct node* temp = s->lst;
here how it should look like
Sequence new_sequence()
{
Sequence s = malloc(sizeof(struct sequence));
if(!s)
{
printf("Out of memory. Can't allocate s\n");
exit(EXIT_FAILURE);
}
s->lst = malloc(sizeof(struct node));
if(! s->lst) {
printf("Out of memory. Can't allocate lst\n");
}
s->lst->rest = NULL;
s->length = 0;
return s;
}
also s->lst->rest has to be set to NULL, this is what tells that the list has no more elements an not end witch turns obsolete.
struct sequence
{
struct node* lst;
int length;
};
You should be passing the sequence itself to your functions not a pointer to some internal data in the sequence.
add_to_front(&temp, item);
Your sequence_insert_at function should be the one that can handle any position not add_to_front() so it is easier to call with the position 0 from add_to_front() and your having the the hole work done in one function, not a half here and a half there.
void sequence_insert_at(Sequence s, int pos, int item)
{
if(s && pos <= s->length) {
print_sequence(s);
struct node *newnode = malloc(sizeof(struct node));
if (newnode == NULL) {
printf("ERROR! add_to_front ran out of memory!\n");
exit(EXIT_FAILURE);
}
newnode->first = item;
struct node* temp = s->lst;
struct node* prv = NULL;
for(int i = 0; i < pos; i++) {
printf("skip %d\n", temp->first);
prv = temp;
temp = temp->rest;
}
newnode->rest = temp;
if(pos == 0) {
printf("insert as first\n");
s->lst = newnode;
} else {
printf("insert before %d\n", temp->first);
prv->rest = newnode;
}
++s->length;
}
}
and in add_to_front only one statement is needed
void add_to_front(Sequence s, int item) {
sequence_insert_at(s, 0, item);
}
as for inserting at the back of the list
void add_to_back(Sequence s, int item) {
sequence_insert_at(s, s->length, item);
}
A small test with the main function
void print_sequence(Sequence s)
{
struct node* temp = s->lst;
for(int i = 0; i < s->length; temp = temp->rest) {
printf("%d ", temp->first);
i++;
}
printf("\n");
}
int main()
{
Sequence derp = new_sequence();
sequence_insert_at(derp, 0, 14);
add_to_front(derp, 16);
sequence_insert_at(derp, 0, 17);
sequence_insert_at(derp, 2, 15);
add_to_back(derp, 13);
print_sequence(derp);
delete_sequence(derp);
return 0;
}
output is:
17 16 15 14 13
You'll have to go trough the other functions and fix them.
Finally i should note that variable names you have choosen are little bit confusing if not misleading, i would name them this way
typedef struct node {
int data; /* the data that a node holds */
struct node* next; /* the pointer to the next node */
} Node_t;
typedef struct sequence {
struct node* head; /* head or first element of the sequence/list */
int length; /* length is ok but size is better */
} Sequence_t;

Resources