preorder array from binary tree - c

I cannot seem to get this function to work. It is supposed to find the preorder of a given binary tree, and put those integers into an array. This function was adapted from a similar print preorder traversal that can be found on geeksforgeeks.
//node struct
typedef struct node
{
// Each node holds a single integer.
int data;
// Pointers to the node's left and right children.
struct node *left, *right;
} node;
node *create_node(int data)
{
node *n = calloc(1, sizeof(node));
n->data = data;
return n;
}
unsigned int node_count_recursive(node *root)
{
unsigned int count = 1;
if (root->left != NULL)
count += node_count_recursive(root->left);
if (root->right != NULL)
count += node_count_recursive(root->right);
return count;
}
unsigned int node_count(node *root)
{
unsigned int count = 0;
if (root != NULL)
count = node_count_recursive(root);
return count;
}
// helper function that takes in the root, a dynamically allocated array, and count variable
// initialized to 0
// problem I believe is in this function
unsigned int preorder_helper(node *root, int *array, unsigned int count)
{
if (root == NULL)
return 0;
// This does not work
array[count++] = root->data;
count = preorder_helper(root->left, array, count);
count = preorder_helper(root->right, array, count);
return count;
}
// creates dynamically allocated array for helper function.
int *preorder_array(node *root)
{
int *array = malloc(sizeof(node) * node_count(root));
preorder_helper(root, array, 0);
return array;
}
// creates tree
int main(void)
{
node *root1;
int *preArray;
root1 = create_node(23);
root1->left = create_node(12);
root1->left->left = create_node(5);
root1->left->right = create_node(18);
root1->right = create_node(71);
root1->right->right = create_node(56);
// points preArray pointer to function
preArray = preorder_array(root1);
// loops through each integer in array
for (int i = 0; i < node_count(root1); i++) //node_count counts nodes in tree
printf("%d ", preArray[i]);
return 0;
}
The preorder_helper function seems to get the first 2 or 3 correct preorder values, but then the rest of the array is 0. The output of this code is this:
56 12 5 0 0 0
Any help is greatly appreciated, thanks.

Related

How can I check if two binary trees contain the same nodes?

I am trying the implement a function which checks whether two binary search trees are equal, order of the nodes not matter. But my implementation does not work.
I am not allowed to flatten the trees into arrays.
this is what I have so far:
int isIdentical(struct Node* root1, struct Node* root2)
{
if (root1 == NULL && root2 == NULL)
return 1;
else if (root1 == NULL || root2 == NULL)
return 0;
else {
if (root1->data == root2->data && isIdentical(root1->left, root2->left)
&& isIdentical(root1->right, root2->right))
return 1;
else
return 0;
}
}
when supplied with trees containing the nodes tree A = 2 4 5 6 and Tree B = 2 5 4 6, the output should be:
1, meaning they are equal, but instead I am getting 0. I am not sure where I am going wrong.
This is how Node is implemeted:
struct Node {
int data;
struct Node* left;
struct Node* right;
};
Make a recursive function that traverses treeA and checks that every item is present in treeB. On failure it abandons the search and returns 0 for failure. It can be your function
int isIdentical(struct Node* root1, struct Node* root2)
If success, call the function again with the arguments for treeA and treeB reversed. The 'check if present' operation can be iterative and inline, because it does not need to backtrack.
Example untried code, to give the idea.
int isAllFound(struct Node* root1, struct Node* root2)
{
// recursive parse of tree 1
if (root1 == NULL)
return 1;
// iterative search of tree 2
int found = 0;
struct Node *root = root2;
while(root != NULL) {
if(root1->data == root->data) {
found = 1;
break;
}
if(root1->data < root->data)
root = root->left;
else
root = root->right;
}
if(!found)
return 0;
// continue recursive parse of tree 1
if(!isAllFound(root1->left, root2))
return 0;
if(!isAllFound(root1->right, root2))
return 0;
return 1;
}
Then call like
if(isAllFound(treeA, treeB) && isAllFound(treeB, treeA))
puts("Success!");
If every item of treeA can be found in treeB, and every item of treeB can be found in treeA then they contain the same data. Provided the keys are unique.
Why do you think they are equal? They are not.
tree A is represented as 2 4 5 6 which I guess you obtained by some sort of pre-order or level-order traversal. If your tree B (2, 5, 4, 6) is equal then with the same sort of traversal you'd obtain same order. They are not equal if the traversal is the same.
Order of nodes doesn't matter:
If the order of the nodes doesn't matter. One thing you could do is do an inorder traversal for both trees and you get a sorted array from both. Then compare both arrays element by element and declare equal or not.
Your function will only compare as equal 2 trees that have exactly the same structure. If the trees are balanced differently, the comparison will return 0 even if the values are identical.
Performing this comparison is non trivial as the trees can have an arbitrary depth if they are not balanced.
You can walk the first tree in depth first order to populate an array and then walk the second tree in depth first order, checking that the values are identical to those in the array.
Here is a simple implementation:
#include <stdlib.h>
struct Node {
int data;
struct Node* left;
struct Node* right;
};
size_t tree_length(const struct Node *root) {
return root ? 1 + tree_length(root->left) + tree_length(root->right) : 0;
}
void tree_store(int *array, size_t *pos, struct Node *node) {
if (node) {
tree_store(array, pos, node->left);
array[++*pos - 1] = node->data;
tree_store(array, pos, node->right);
}
}
int tree_check(int *array, size_t *pos, struct Node *node) {
if (node) {
return tree_check(array, pos, node->left)
&& array[++*pos - 1] == node->data
&& tree_check(array, pos, node->right);
} else {
return 1;
}
}
/* compare trees: return 0 if different, 1 if same values, -1 if allocation error */
int isIdentical(const struct Node *root1, const struct Node *root2) {
size_t len1 = tree_length(root1);
size_t len2 = tree_length(root2);
size_t pos;
if (len1 != len2)
return 0;
if (len1 == 0)
return 1;
int *array = malloc(sizeof(*array) * len1);
if (!array)
return -1;
pos = 0;
tree_store(array, &pos, root1);
pos = 0;
int res = tree_check(array, &pos, root2);
free(array);
return res;
}
If you are not allowed to convert the trees to arrays, you could:
normalize both trees, then use your simple comparator, but this will modify the trees and is difficult.
implement a stack based iterator and iterate both trees in parallel.
Here is a simple implementation of the latter:
#include <stddef.h>
struct Node {
int data;
struct Node *left;
struct Node *right;
};
size_t max_size(size_t a, size_t b) {
return a < b ? b : a;
}
size_t tree_depth(const struct Node *root) {
return root ? 1 + max_size(tree_depth(root->left), tree_depth(root->right)) : 0;
}
int tree_next(const struct Node **stack, size_t *ppos, int *value) {
size_t pos = *ppos;
if (stack[pos] == NULL) {
if (pos == 0)
return 0; // no more values
pos--;
} else {
while (stack[pos]->left) {
stack[pos + 1] = stack[pos]->left;
pos++;
}
}
*value = stack[pos]->data;
stack[pos] = stack[pos]->right;
*ppos = pos;
return 1;
}
/* compare trees: return 0 if different, 1 if same values, -1 if allocation error */
int isIdentical(const struct Node *root1, const struct Node *root2) {
if (root1 == NULL || root2 == NULL)
return root1 == root2;
size_t depth1 = tree_depth(root1);
size_t depth2 = tree_depth(root2);
const struct Node *stack1[depth1];
const struct Node *stack2[depth2];
size_t pos1 = 0;
size_t pos2 = 0;
stack1[pos1++] = root1;
stack2[pos2++] = root2;
for (;;) {
int value1, value2;
int has1 = tree_next(stack1, &pos1, &value1);
int has2 = tree_next(stack2, &pos2, &value2);
if (!has1 && !has2)
return 1;
if (!has1 || !has2 || value1 != value2)
return 0;
}
}

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];
}

function to create array of post order binary tree

Im trying to create a recursive function that creates an array of post order integers from a given tree. This is the code:
//structure
typedef struct node
{
// Each node holds a single integer.
int data;
// Pointers to the node's left and right children.
struct node *left, *right;
} node;
// preorder_recursive is same as postorder_recursive(), except
// array[i] comes before the recursive calls
int *postorder_recursive(node *root)
{
int *array = malloc(sizeof(node) * node_count(root)); // node_count(root) counts nodes in binary tree
int i = 0;
if (root == NULL)
return 0;
while (root != NULL)
{
postorder_recursive(root->left);
postorder_recursive(root->right);
array[i] = root->data;
i++;
}
return array;
}
// returns 1 if pre order = post order, returns 0 otherwise
int compare(node *a, node *b)
{
int i = 0;
int *preArray, *postArray;
if (node_count(a) != node_count(b))
return 0;
preArray = preorder_recursive(a);
postArray = postorder_recursive(b);
for (i = 0; i < node_count(a); i++)
{
if (preArray[i] != postArray[i])
return 0;
}
free(preArray);
free(postArray);
return 1;
}
I am not entirely sure if the error is in this function, but if it is, it's probably due to the while loop. Any help would be great.
Edit: Ive included a lot more code. The purpose of this is to compare an array of post order to an array of pre-order.
Your function postorder_recursive() is creating a new array every time it is called. Furthermore, while(root != NULL) will loop forever for non-empty trees, if it weren't for the fact that it writes past the end of array and cause a segmentation fault at some point.
The solution is to split the function into one that creates the array, and then another function that recursively fills in the array, like so:
static size_t postorder_recursive(const node *root, int *array, size_t index) {
if (root == NULL)
return index;
index = postorder_recursive(root->left, array, index);
index = postorder_recursive(root->right, array, index);
array[index++] = root->data;
return index;
}
int *postorder_to_array(const node *root)
{
int *array = malloc(sizeof(node) * node_count(root));
postorder_recursive(root, array, 0);
return array;
}

Preorder tree traversal function which returns an array of integers in C

I try to write a function which return an array of integers containing the node values of the binary tree in preorder that is a node value must appear before the values of its left and right child.
if root is NULL, return NULL
for every node left child comes before right child
For example;
int *a = preorder(bt1);
for (i=0; i<3; i++)
printf("%d ", a[i]);
>2_1_3_
Here is my work, but it doesn't work, where could be the problem in my code?
int* preorder(TreeNode *root) {
int *a = malloc(sizeof(int)*50);
int i=0;
if(root == NULL)
return NULL;
else {
if(root != NULL) {
a[i] = root->val;
i++;
preorder(root->left);
preorder(root->right);
return a;
}
}
}
You have two issues in the code:
You have to allocate the array for results once. Before calling preorder
You have to keep i outside of preorder to allow it to change between calls
One example is the following code:
int *a = malloc(sizeof(int)*50);
int inx = 0;
preorder(bt1, a, &inx);
void preorder(TreeNode *root, int* a, int* inx) {
if(root == NULL)
return;
else {
if(root != NULL) {
a[*inx] = root->val;
*inx = *inx + 1;
preorder(root->left, a, inx);
preorder(root->right, a, inx);
}
}
}
In each recursive call of this function you will allocate:
int *a = malloc(sizeof(int)*50);
You need to allocate space for array once and then use that same array. Same thing is for using i = 0. You need to use one counter.
You may want create array in main function, and then pass array as function argument. Or you could use global array, and access it that way. Same thing for counter variable.
Note: I don't see point of memory allocation in your example. You should better use static array if you're sure that tree won't have more then ARRAY SIZE nodes.
With the wanted function signature of preorder() a solution is not possible. Therefore you need a helper function for the root == NULL case and a traversal function which a pointer to the current position in the array. It also returns a pointer to the next free slot in the array. A solution could look like:
#include <stdio.h>
#include <malloc.h>
struct TreeNode {
int val;
struct TreeNode* left, * right;
};
int tree_size(/*struct TreeNode* tree*/) { return 7; }
int* preorder_(struct TreeNode* tn, int* v) {
*v++ = tn->val;
if (tn->left) v = preorder_(tn->left, v);
if (tn->right) v = preorder_(tn->right, v);
return v;
}
int* preorder(struct TreeNode* tn) {
if (tn) {
int* v = malloc(tree_size(/*tn*/) * sizeof(int));
preorder_(tn, v);
return v;
} else {
return NULL;
}
}
int main(void) {
// 4
// 2 5
// 1 3 6 7
struct TreeNode
left = {2, &{1}, &{3]},
right = {5, &{6}, &{7}},
root = {4, &left, &right};
int *v, i;
v = preorder(&root);
for (i = 0; i < tree_size(/*tn*/); i++) {
printf("%d ", v[i]); // 4 2 1 3 5 6 7
}
free(v);
return 0;
}
Live Demo

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