function to create array of post order binary tree - c

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

Related

How to use double pointers in binary search tree data structure in C?

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.

Store tree structured data to an array in C

I am trying to write a code to transverse a tree data structure using inorder transversal and store all the nodes onto an array.
I came up with this code below but it doesn't work, as the index of any previous recursion has already been passed on in the function.
int *inorderTransversal(AVLTreeNode *node, AVLTreeNode *array[], int index)
{
if (node == NULL)
return index;
inorderTransversal(node->left, array, index);
nodesArray[index] = node;
index++;
inorderTransversal(node->right, array, index);
return index;
}
I know I could possibly declare a static 'index' value inside the function, and it might work? But the downside is it makes 'index' stays in the memory for the entire duration of the program e.g.
void *inorderTransversal(AVLTreeNode *node, AVLTreeNode *array[])
{
static int index = 0;
if (node == NULL)
return;
inorderTransversal(node->left, array);
nodesArray[index] = node;
index++;
inorderTransversal(node->right, array);
return;
}
Or I could declare the index outside the function prior? e.g.
AVLTreeNode *array[tree->size];
int index = 0;
void *inorderTransversal(AVLTreeNode *node) {
if (node == null)
return;
inorderTransversal(node->left);
array[index] = node;
index++;
inorderTransversal(node->right);
}
Could someone help me to amend the code to include the 'index' increments inside the function without using static? Much appreciated!
Your first attempt was close. You want to pass in index as an int *. Then you can dereference it and update it.
void inorderTransversal(AVLTreeNode *node, AVLTreeNode *array[], int *index)
{
if (node == NULL)
return;
inorderTransversal(node->left, treeSize, index);
nodesArray[*index] = node;
(*index)++;
inorderTransversal(node->right, treeSize, index);
}
When you call this function, you pass the address of an int which has been initialized to 0. When the recursion ends it will hold the number of elements in the list.

preorder array from binary tree

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.

Counting the nodes of any tree time improvement

I have to make a function which counts how many elements my tree have. My tree is not binary, is the most general kind of tree.
The node is:
typedef struct node{
char item;
int number_of_sons;
node **sons;
}
My counting function is this
void numbering(node *HT,int ok=0)
{
static int number = 0;
if (ok == 1)
{
printf("%d", number);
return;
}
if (HT == NULL)
{
return;
}
else
{
number++;
for (int i = 0;i < HT->nr_of_sons;i++)
{
numbering(HT->next[i], 0);
}
}
}
Is there a way to improve this function to make this faster?
EDIT: the way I use this function is:
int main()
{
//create tree;
numbering(tree,0);
numbering(tree,1);
}
When I call the function the second time it prints my result
You have a very strange recursive function there--you're using a static variable in the function which is never reset, so the function can only be used once per program run!
I'd rewrite it this way:
size_t nodecount(node *root)
{
size_t count = 0;
if (root)
{
count++;
for (int i = 0; i < root->nr_of_sons; i++)
{
count += nodecount(root->sons[i]);
}
}
return count;
}
If you really want to speed things up, you could augment your node structure by adding a size_t subtree_count field which you'd maintain whenever you insert or remove nodes. Another idea is to compact the pointer-to-array-of-sons into the node structure directly:
typedef struct node{
char item;
int number_of_sons;
node_t *sons[0];
} node_t;
What I've done here is made it so the sons variable is an array rather than a pointer to an array. But it has size zero (n.b. use [] or [1] if your compiler requires), because you don't know the number of sons at compile time. But you can simply allocate nodes with the right amount of space:
node_t* tree = (node_t*)malloc(sizeof(node_t) + num_sons*sizeof(node_t*));
This reduces pointer indirection by one layer, which may help performance.
Maybe this is better and more efficient:
int numbering(node *HT)
{
if (!HT)
{
return 0;
}
int num = 1;
for (int i = 0;i < HT->nr_of_sons;i++)
{
num += numbering(HT->next[i]);
}
return num;
}
I deleted your ok variable and changed the returned value from void to int.
In the case base you return 0;
For the leaf so they will return 1;
For inner nodes they will return 1 + the numbers of nodes in the
subtree.

How to free memory occupied by a Tree, C?

I'm currently dealing with a generic Tree with this structure:
typedef struct NODE {
//node's keys
unsigned short *transboard;
int depth;
unsigned int i;
unsigned int j;
int player;
int value;
struct NODE *leftchild; //points to the first child from the left
struct NODE *rightbrothers; //linked list of brothers from the current node
}NODE;
static NODE *GameTree = NULL;
While the function that allocates the different nodes is (don't bother too much at the keys' values, basically allocates the children-nodes. If there aren't any the new child goes to leftchild, otherwise it goes at the end of the list "node->leftchild->rightbrothers"):
static int AllocateChildren(NODE **T, int depth, unsigned int i, unsigned int j, int player, unsigned short *transboard) {
NODE *tmp = NULL;
if ((*T)->leftchild == NULL) {
if( (tmp = (NODE*)malloc(sizeof(NODE)) )== NULL) return 0;
else {
tmp->i = i;
tmp->j = j;
tmp->depth = depth;
(player == MAX ) ? (tmp->value = 2 ): (tmp->value = -2);
tmp->player = player;
tmp->transboard = transboard;
tmp->leftchild = NULL;
tmp->rightbrothers = NULL;
(*T)->leftchild = tmp;
}
}
else {
NODE *scorri = (*T)->leftchild;
while (scorri->rightbrothers != NULL)
scorri = scorri->rightbrothers;
if( ( tmp = (NODE*)malloc(sizeof(NODE)) )== NULL) return 0;
else {
tmp->i = i;
tmp->j = j;
tmp->depth = depth;
(player == MAX) ? (tmp->value = 2) : (tmp->value = -2);
tmp->player = player;
tmp->transboard = transboard;
tmp->leftchild = NULL;
tmp->rightbrothers = NULL;
}
scorri->rightbrothers = tmp;
}
return 1;
}
I need to come up with a function, possibly recursive, that deallocates the whole tree, so far I've come up with this:
void DeleteTree(NODE **T) {
if((*T) != NULL) {
NODE *tmp;
for(tmp = (*T)->children; tmp->brother != NULL; tmp = tmp->brother) {
DeleteTree(&tmp);
}
free(*T);
}
}
But it doesn't seem working, it doesn't even deallocate a single node of memory.
Any ideas of where I am being wrong or how can it be implemented?
P.s. I've gotten the idea of the recursive function from this pseudocode from my teacher. However I'm not sure I've translated it correctly in C with my kind of Tree.
Pseudocode:
1: function DeleteTree(T)
2: if T != NULL then
3: for c ∈ Children(T) do
4: DeleteTree(c)
5: end for
6: Delete(T)
7: end if
8: end function
One thing I like doing if I'm allocating lots of tree nodes, that are going to go away at the same time, is to allocate them in 'batches'. I malloc then as an array of nodes and dole them out from a special nodealloc function after saving a pointer to the array (in a function like below). To drop the tree I just make sure I'm not keeping any references and then call the free routine (also like below).
This can also reduce the amount of RAM you allocate if you're lucky (or very smart) with your initial malloc or can trust realloc not to move the block when you shrink it.
struct freecell { struct freecell * next; void * memp; } * saved_pointers = 0;
static void
save_ptr_for_free(void * memp)
{
struct freecell * n = malloc(sizeof*n);
if (!n) {perror("malloc"); return; }
n->next = saved_pointers;
n->memp = memp;
saved_pointers = n;
}
static void
free_saved_memory(void)
{
while(saved_pointers) {
struct freecell * n = saved_pointers;
saved_pointers = saved_pointers->next;
free(n->memp);
free(n);
}
}
I've just realized my BIG mistake in the code and I'll just answer myself since no one had found the answer.
The error lies in this piece of code:
for(tmp = (*T)->children; tmp->brother != NULL; tmp = tmp->brother) {
DeleteTree(&tmp);
}
First of all Ami Tavory was right about the for condition, i need to continue as long as tmp != NULL
Basically it won't just work because after the DeleteTree(&tmp), I can no longer access the memory in tmp because it's obviously deleted, so after the first cycle of for ends I can't do tmp = tmp->rightbrother to move on the next node to delete because tmp->rightbrother no longer exists as I just deleted it.
In order to fix it I just needed to save the tmp->brother somewhere else:
void DeleteTree(NODE **T) {
if((*T) != NULL) {
NODE *tmp, *deletenode, *nextbrother;
for(tmp = (*T)->children; tmp != NULL; tmp = nextbrother) {
nextbrother = tmp->rightbrother;
DeleteTree(&tmp);
}
canc = (*T);
free(*T);
(*T) = NULL;
}
}
Just for the sake of completeness I want to add my version of DeleteTree
void DeleteTree(NODE *T) {
if(T != NULL) {
DeleteTree(T->rightbrothers);
DeleteTree(T->leftchild);
free(T);
}
}
I think it is much less obscure and much easier to read. Basically it solves the issue in DeleteTree but through eliminating the loop.
Since we free the nodes recursively we might as well do the whole process recursively.

Resources