Convert heap implemented in array to tree - c

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.

Related

How to add node to binary tree in C?

How do I add more nodes to my binary tree if A (left) and B (right) are already full? I just need to create a tree that is balanced. But I can't figure out how to add more data to the tree. Any help would be greatly appreciated.
Thanks in advance for any tipps.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
struct node
{
char *titel;
struct node *A;
struct node *B;
};
void display(struct node *leaf)
{
if (leaf != NULL)
{
display(leaf->A);
printf("%s\n",leaf->titel);
display(leaf->B);
}
}
struct node *insert(char* titel, struct node **leaf)
{
if (*leaf == 0)
{
*leaf = (struct node*)malloc(sizeof(struct node));
(*leaf)->titel = malloc(strlen(titel)+1);
strcpy((*leaf)->titel,titel);
(*leaf)->A = NULL;
(*leaf)->B = NULL;
}
else if ((*leaf)->A == NULL)
{
(*leaf)->A = insert(titel,&(*leaf)->A);
}
else if ((*leaf)->B == NULL )
{
(*leaf)->B = insert(titel,&(*leaf)->B);
}
//WHAT TO ADD HERE TO CREATE ANOTHER NODE?
return(*leaf);
}
int main(int argc, char const *argv[])
{
struct node *root = NULL;
insert("root",&root);
insert("chapter_1A",&root);
insert("chapter_1B",&root);
insert("chapter_2A",&root);
insert("chapter_2B",&root);
insert("chapter_3A",&root);
display(root);
return 0;
}
Output should be like a balanced binary tree. Mustn't be printed but stored like that in memory.
Actual output:
chapter_1A
root
chapter_1B
root
/ \
chapter_1A chapter_1B
/ \ / \
ch_2A ch_2B ch_3A ch_3B
and so on.
How do I add more nodes to my binary tree if A (left) and B (right) are already full?
By "full" I take it that you mean both child nodes themselves have two children. In this case, any new node must be added to one of the children of the children. Typically you would do this via a recursive function, so that it correctly handles the case when the children's children are also "full", and so on.
I just need to create a tree that is balanced
(Note that "balanced" can itself mean several things. For instance, there are "height balanced" and "weight balanced" trees. You don't specify which you want).
The question then is which (full) child to add a new node to - right or left? One option is to keep a count of the total descendants of each node, and always add to the child which has the fewest.
Another option is to keep count of the total number of nodes in the tree, and use the bits in that number (ignoring the first 1 bit) to decide on where to insert the new node. For example, if you have a tree with 5 nodes:
A
B C
D E
To add a new node, increment the node count to 6, which is 110 in binary. Ignore the first 1; interpret the next 1 as "go right" (which takes you to C) and the following 0 as "go left" (which tells you to insert as the left child of C). Your code becomes something like this:
void insert(char* titel, struct node **leaf, int nodeCount, int bitPos)
{
if (*leaf == 0)
{
*leaf = (struct node*)malloc(sizeof(struct node));
(*leaf)->titel = malloc(strlen(titel)+1);
strcpy((*leaf)->titel,titel);
(*leaf)->A = NULL;
(*leaf)->B = NULL;
}
else
{
int currentBit = (nodeCount >> bitPos) & 1;
if (currentBit == 0) {
// insert to left
insert(titel, &((*leaf)->A), nodeCount, bitPos - 1);
}
else
{
// insert to right
insert(titel, &((*leaf)->B), nodeCount, bitPos - 1);
}
}
}
Notice I changed the return type to void since you don't need to return a value. I'll leave the calculation of the initial bitPos value as an exercise (remember: it's the position of the highest order 1 bit, minus 1).
If you also need to remove elements from the tree, you will need to find a way to re-balance it, however.
Note that there are several data structures and algorithms for maintaining balanced trees which support both insertion and deletion. See red-black trees and AVL trees for example. These are usually used for ordered trees, but it should be trivial to adapt them for an unordered-but-balanced tree.

Inserting millions of Elements into a Binary Search Tree BST

I have been trying to solve this issue for almost 3 days with no luck yet. I am trying to insert many elements is size of (5 million)of unsigned integer into a binary tree.
This code works fine when I limit the total elements to be inserted into 10K, however, it does not work when I set the total elements to be 5 million.
I am running this code on my PC which has:
Windows 7 - 32
RAM 4 GB
Any help would be really appreciated. Thanks in advance :)
Here is my code:
#include<stdlib.h>
#include<stdio.h>
typedef int ElementType;
typedef struct TreeNode {
ElementType element;
struct TreeNode *left, *right;
} TreeNode;
TreeNode *createTree(){
//Create the root of tree
TreeNode *tempNode;
tempNode = malloc(sizeof(TreeNode));
tempNode->element = 0;
tempNode->left = NULL;
tempNode->right = NULL;
return tempNode;
}
TreeNode *createNode(ElementType X){
//Create a new leaf node and return the pointer
TreeNode *tempNode;
tempNode = malloc(sizeof(TreeNode));
tempNode->element = X;
tempNode->left = NULL;
tempNode->right = NULL;
return tempNode;
}
TreeNode *insertElement(TreeNode *node, ElementType X){
//insert element to Tree
if(node==NULL){
return createNode(X);
}
else{
if(X < node->element){
node->left = insertElement(node->left, X);
return node; // add this.
}
else if(X > node->element){
node->right = insertElement(node->right, X);
return node; // add t
else if(X == node->element){
printf("Oops! the element is already present in the tree.");
}
}
}
TreeNode *displayTree(TreeNode *node){
//display the full tree
if(node==NULL){
return;
}
displayTree(node->left);
printf("| %d ", node->element);
displayTree(node->right);
}
main(){
//pointer to root of tree #2
TreeNode *TreePtr;
TreeNode *TreeRoot;
TreeNode *TreeChild;
//Create the root of tree
TreePtr = createTree();
TreeRoot = TreePtr;
TreeRoot->element = 32;
for ( int i=0; i < 5000000; i ++)
insertElement(TreeRoot, i);
displayTree(TreeRoot);
}
Any help would be really appreciated. Thanks in advance :)
Assuming that you have no other errors in your code, always inserting 8 will degenerate the tree to a list, and I think, your stack will overflow at some recursion level far below the 5 million.
To generally avoid a degenerated tree, I would advise you to use the insert/deletion semantics of an AVL-Tree.
This has the advantage, that your datastructures can remain as they are, but you only have to adapt the insert and delete procedures.
Edit: In your comment, you state now that you do not insert always 8 but i. This means, you insert pre-sorted elements into the binary tree, which also degenerates it to a list, so the same problem arises as with always inserting "8".
It looks like:
1
\
2
\
3
\
4
\
...
after inserting the elements in order.
An AVL-Tree will not suffer from that problem:
https://en.wikipedia.org/wiki/AVL_tree
OK Faisal.
If you insert the value of i, then you will always insert a key greater than all the keys currently contained in the tree. Consequently you will get a tree of maximum height, which in performance (and shape too) is equivalent to a list. Since you algorithm is recursive, you will get a stack overflow very quickly.
A possible way for dealing with you problem, but is not a guarantee for avoiding an overflow, is to insert random keys. Theoretically, the average on the number of nodes revised in an unsuccessful search is O(log N).
So you could use the rand() for getting random numbers or a more sophisticated and sure random number generator.

Finding specific values in a Tree

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 :)

Simple inorder tree traversal giving a non terminating loop. (using arrays)

Following is my code for building a simple tree. The approach I'm using here is that if a particular node is at index n in the arr[] array, then it has it's left child at index 2*n+1 and right child at 2*n+2 in the same arr[] array. And then I'm doing an inorder traversal. However, I'm getting an infinite loop at node D as my output. Would love if anybody could help me out here.
#include <stdio.h>
#include <malloc.h>
struct node
{
struct node * lc;
char data;
struct node * rc;
};
char arr[] = {'A','B','C','D','E','F','G','\0','\0','H','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
struct node * root = NULL;
struct node * buildTree(int rootIndex)
{
struct node * temp = NULL;
if(arr[rootIndex]!='\0')
{
temp = (struct node *)malloc(sizeof(struct node));
temp->lc = buildTree(rootIndex * 2 + 1);
temp->data = arr[rootIndex];
temp->rc = buildTree(rootIndex * 2 + 2);
}
return temp;
}
void inorder(struct node * parent)
{
while(parent != NULL)
{
inorder(parent->lc);
printf("%c\t",parent->data);
inorder(parent->rc);
}
}
int main()
{
root = buildTree(0);
inorder(root);
return 0;
}
Like BLUEPIXY mentioned in comments, you need to replace the while in inorder() method with an if. When building tree, D forms the left-most child. Therefore during in-order traversal, D is encountered as the first node to be printed. But the while loop keeps printing it as the condition never becomes false.
I'm sure a tool like gdb would have done much better job in explaining this.

binary tree: user decides whether it should be a number tree or a word tree in c programming

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#.

Resources