Well, I've been at it for a while...trying to figure out an algorithm to insert my list of random numbers into a binary tree.
This is what I have gotten so far:
NodePtr and Tree are pointers to a node
NodePtr CreateTree(FILE * fpData)
{
int in;
fscanf(fpData, "%i", &in);
Tree T = (NodePtr)malloc(sizeof(Node));
T->Left = NULL;
T->Right = NULL;
T->value = in;
while((fscanf(fpData, "%i", &in)) != EOF)
{
InsertInTree(in, T);
printf("\n %p", T);
}
return T;
}
void InsertInTree(int value,Tree T)
{
if(T == NULL)
{
T->Left = (NodePtr)malloc(sizeof(Node));
T->Left->Left = NULL;
T->Left->Right = NULL;
T->Left->value = value;
printf("\n %i ", value);
return;
}
if(T->Left == NULL)
{
InsertInNull(value, T->Left);
}
else if(T->Right == NULL)
{
InsertInNull(value, T->Right);
}
else
{
if(T->Left->Left == NULL || T->Left->Right == NULL) InsertInTree(value, T->Left);
else InsertInTree(value, T->Right);
}
}
I'm lost on what to do if the both children of a particular node are not null. What I did here works for a small amount of numbers (1,2,3,5,6) but if the list is larger it becomes unbalanced and wrong.
Is it meant to be a search-tree? I don't see any if (value < T->Value) conditions.
And you have an InsertNull (not shown). That shouldn't be necessary, 1 function should be enough.
To address your main problem, use a pointer-to-pointer parameter or, more elegant, always return a new Tree:
//untested, no balancing
Tree InsertValue(Tree t, int value)
{
if (t == null)
t = // create and return new node
else
{
if (value < t->Value)
t->Left = InsertValue(t->Left, value);
else
t->Right = InsertValue(t->Left, value);
}
return t;
}
And in CreateTree:
Tree t = InsertValue(null, in);
Since the assignment is not for a sorted tree, you can populate it in a breadth-first manner. This means the first thing inserted is always the root, the next is the first node at the next level so it looks like this:
0
1 2
3 4 5 6
Here is an article that explains it further:
http://www.cs.bu.edu/teaching/c/tree/breadth-first/
Simple insertion in a binary tree and keeping a binary tree balanced are different problems. I suggest you start with the first problem and just focus on keeping order properties correct within the tree. Your are not far from that.
Then you should have a look at classical implementations for red-black trees, well studied and efficient way of keeping trees balanced, but with a cost, it's more complex.
Related
I am trying to find the depth of a specific node noted by a pointer in c, but I cant seem to get it right
int depth(Node *root, Node *N){
// Need to find the root N
// At the same time count how many depths you can go down
// If the root is NULL, then no tree and return -1
if (root == NULL){
return -1;
}
// If the root node equals the node N, then return 0
if (root->data == N->data){
return 0;
}
// Search the tree and add one each time recursion called
int count = -1;
if (N->data < root->data){
root->left->data = depth(root->left, N);
count++;
}
else if (N->data > root->data){
root->right->data = depth(root->right, N);
count++;
}
else{
}
return count;
}
Any help in solving this would be appreciated.
The pseudo code for such a function is along the lines of this, assuming root = level 0:
int search (const node_t* node, int level)
{
if(node == NULL)
return -1;
if(node->data == key)
return level;
const node_t* node next;
if(node->data < key)
next = node->right;
else if(node->data > key)
next = node->left
return search (next, level+1);
}
First called as search(root, 0);
Though as usual, recursion in C is almost certainly the wrong solution to any problem. The above can rather trivially be rewritten as sane, readable, fast loops instead.
Is there any way to insert a new node in a binary tree (not bst) without comparing key values? The following code only works for the very first three nodes.
node *insert (node *root, int *key) {
if (root==NULL) {
root=newNode(root, key);
return root;
}
else if (root->left == NULL)
root->left=insert(root->left,key);
else if (root-> right == NULL)
root->right=insert(root->right,key);
return root;
}
If you change
else if (root-> right == NULL)
to just
else
Then it would have the effect of always adding to the right.
If you want it to randomly pick, add a call to srand outside this function.
srand(time(NULL));
Then in this function, call
else if (rand() > MAX_RAND / 2) {
root->right = insert(root->right, key);
} else {
root->left = insert(root->left, key);
}
at the end of your existing if/else structure.
See also:
Lack of randomness in C rand()
If your tree tracks its height at each node, you could add after your null checks something like
else if (root->left->height <= root->right->height) {
root->left = insert(root->left, key);
} else {
root->right = insert(root->right, key);
}
That would keep the tree balanced automatically. But it requires additional code to manage the height. E.g.
root->height = 1 + ((root->left->height > root->right->height) ? root->left->height : root->right->height);
I leave it up to you whether that additional overhead is worth it.
The people suggesting using a heap are suggesting using the indexes as the ordering. This is kind of useless as a heap, but it would make a balanced binary tree. So the root node would be the first inserted and the most recent inserted would be the rightmost leaf.
You could just keep track of the height of each node, and always insert it into the side with fewer children:
node *insert (node *root, int *key) {
if (root==NULL) {
root=newNode(root, key);
root->height = 0
}
else if (root->left == NULL) {
insert(root->left,key);
}
else if (root->right == NULL) {
insert(root->right,key);
}
else if (root->left->height <= root->right->height) {
insert(root->left,key);
} else {
insert(root->right,key);
}
root->height++
}
Comparing values is actually irrelevant, the only think you need to do is set a pointer. Since you didn't specify any real requirements, one solution could be as follows:
Changing the signature a bit so now you have a pointer to an already allocated node:
void insertNode(node *&root, node *newNode) {
if (root == NULL) {
root = newNode;
return;
}
if (root->left == NULL) {
root-left = newNode;
return;
}
helperInsert(root->left, newNode);
return;
}
This will set the head (assuming I got the signature right), and otherwise check the left child.
void helperInsert(node *it, node *newNode) {
if (it->left == NULL) {
it->left = newNode;
return;
}
helperInsert(it->left, newNode);
return;
}
This is obviously a flawed approach (the tree will not be balanced at the slightest), almost treating the tree as a linked list, but to my best understanding of the question, this is an example of how it can be done.
In
else if (root->left == NULL)
root->left=insert(root->left,key);
you know root->left is NULL so why to do the recursive call ?
Of course same for the next else
The following code only works for the very first three nodes.
If both left and right are non NULL you do not insert, that time it was necessary to do the recursive call on one of the two branches, and you will consider the key (so insert ordered) to decide which one. Note that the 2 tests to NULL you did are not correct if you insert to have a sorted tree ...
The heap advice is most sound. You don't need to heapify anything, just follow the rules that an element at index k has children at 2*k + 1 and 2*k + 2.
Another approach, useful when there is no array, but the nodes are generated on the fly, is to fill the tree level-wise. Notice that at level k there are 2 ** k slots, conveniently indexed by a k-bit integer. Interpret the index as a path down the tree (clear bit tells to follow left child, set bit tells to follow a right one), along the lines of:
void insert_node(struct node * root, struct node * node, unsigned mask, unsigned path)
{
while ((mask >> 1) != 1) {
root = mask & path? root->right: root->left;
}
if (mask & path) {
assert (root->right == NULL);
root->right = node;
} else {
assert (root->left == NULL);
root->left = node;
}
}
void fill_level_k(struct node * root, unsigned k)
{
unsigned slots = 1 << k;
for (unsigned slot = 0; slot < slots; slot++) {
struct node * node = generate_new_node();
insert_node(root, node, slots, slot);
}
}
Hello stackoverflowers,
i am facing a problem with my function in C, i want to create a function that give me the min and max value in BST.
The problem is when i use this function it returns the same value for min and max:
void Find_Min_Max(node *bt,int* maxint,int* minint)
{
node *tmp = bt;
if( bt == NULL)
{
*maxint = 0; // Only if the tree contains nothing at all
*minint = 0; // Only if the tree contains nothing at all
}
if( bt->left)
return Find_Min_Max(bt->left,&(*maxint),&(*minint));
*minint = bt->data;
if( tmp->right)
return Find_Min_Max(tmp->right,&(*maxint),&(*minint));
*maxint = tmp->data;
}
But when i use it to give me just one result max/min, i delete this part of code, everything work perfectly:
if( tmp->right)
return Find_Min_Max(tmp->right,&(*maxint),&(*minint));
*maxint = tmp->data;
Any idea how this will work?.
Thank you in advance.
It's not really easy / intuitive to recursively compute max and min at the same time in the same function. I would even say it's not possible, because those are two completely different traversals.
You should have a function to get the minimum, a function to get the maximum, and call each of them inside Find_Min_Max.
This would be a possible approach:
int find_min(node *n) {
if (n == NULL) {
return 0;
}
while (n->left != NULL) {
n = n->left;
}
return n->data;
}
find_max is similar, but traverses right links only:
int find_max(node *n) {
if (n == NULL) {
return 0;
}
while (n->right != NULL) {
n = n->right;
}
return n->data;
}
Then, find_min_max() is easy to code:
void find_min_max(node *bt, int *min, int *right) {
*min = find_min(bt);
*max = find_max(bt);
}
find_min() and find_max() could be recursive, but the iterative approach has the desirable property of using constant memory (and consequently avoids stack overflows).
To find the minimum value in a BST, you follow the chain of left children from the root until you reach a node with no left child. That node contains the minimum value (even if it does have a right child).
The algorithm to find the maximum is exactly the mirror image: follow the chain of right children until you reach a node with no right child. That node contains the maximum value.
It does not make sense to try to perform both traversals at the same time, because they follow completely different paths. If you want a single function to discover both the minimum and the maximum value, then it doesn't make much sense for that function itself to be recursive. It could, however, wrap calls to two separate recursive functions, one to find the minimum, and the other to find the maximum.
Finding min and max value in a BST are very easy. Please check both code snippet below I explain how these codes work.
public int minValueInBST(Node node){
if (node == null) throw new IllegalStateException();
Node current = node;
while (current.leftChild != null) {
current = node.leftChild;
}
return current.value;
}
To find the minimum value in BST we have to find the leftmost leaf node because that node contains the minimum value. So at first, we check the root node is null or not if null we throw IllegalStateException otherwise we find the left node, at last, we return the left node value.
public int maxValueInBST(Node node){
if (node == null) throw new IllegalStateException();
Node current = node;
while (current.rightChild != null) {
current = node.rightChild;
}
return current.value;
}
To find the maximum value in BST we have to find the rightmost leaf node because that node contains the maximum value. So at first, we check the root node is null or not if null we throw IllegalStateException otherwise we find the right node, at last, we return the right node value.
// try this
tree_node *min(tree_node *root)
{
if (!root)
{
printf("Tree is empty");
exit(1);
}
tree_node *ret_val;
if (root->left == NULL)
{
ret_val = root;
}
else
{
ret_val = min(root->left);
}
return ret_val;
}
tree_node *max(tree_node *root)
{
if (!root)
{
printf("Tree is empty");
exit(1);
}
tree_node *ret_val;
if (root->right == NULL)
{
ret_val = root;
}
else
{
ret_val = max(root->right);
}
return ret_val;
}
complete code
I've been playing about with this Binary search tree for a while but I can't seem to insert or change any of the tree properties.
My binary tree is defined as:
struct tree{
Node * root;
int size;
};
struct node{
int value;
Node * left;
Node * right;
};
Therefore my binary tree is composed of nodes. Now the bit that doesn't work:
void add(int value, Tree *t){
//1. if root is null create root
if(t->root == NULL){
t->root = nodeCreate(value);
t->size ++;
return;
}
Node * cursor = t->root;
while(cursor != NULL){
if(value == cursor->value){
printf("value already present in BST\n");
return;
}
if(value < cursor->value){
cursor = cursor->left;
}
if(value > cursor->value){
cursor = cursor->right;
}
}
//value not found in BST so create a new node.
cursor = nodeCreate(value);
t->size = t->size + 1;
}
Can someone tell me where I'm going wrong? I expected calls to add() would increase the size member as well as creating new nodes but I can't seem to get it.
I believe the changes below will fix your problem.
void add(int value, Tree *t){
if(t->root == NULL){
t->root = nodeCreate(value);
t->size ++;
return;
}
Node * cursor = t->root;
Node * last = null;
while(cursor != NULL){
last = cursor;
if(value == cursor->value){
printf("value already present in BST\n");
return;
}
if(value < cursor->value){
cursor = cursor->left;
}
if(value > cursor->value){
cursor = cursor->right;
}
}
//value not found in BST so create a new node.
cursor = nodeCreate(value);
if (value > cursor->value)
{
last->right = cursor;
}
else
{
last->left = cursor;
}
t->size = t->size + 1;
}
You're have both a design flaw and an outright-bug in your loop.
The design flaw: You're allocating a new node, but assigning to cursor doesn't mean you're assigning to the parent node left or right child pointer that got you there in the first place. You need a reference to the actual pointer you're going to populate. One way to do this is with a pointer-to-pointer, and as a bonus, this eliminates the is-my-root-null check at the beginning.
The outright bug: Your left-side movement clause (i.e. chasing a left-side pointer) will potentially change cursor to NULL. but the logic for chasing the right side is not excluded with an else if condition. If your search followed a left-side to null it would fault chasing the right side of a null pointer. This was obviously a problem.
void add(int value, Tree *t)
{
Node **pp = &(t->root);
while (*pp)
{
if(value == (*pp)->value) {
printf("value already present in BST\n");
return;
}
if(value < (*pp)->value)
pp = &(*pp)->left;
else if(value > (*pp)->value)
pp = &(*pp)->right;
}
*pp = nodeCreate(value);
t->size++;
}
I should also note that you can skip the equality check by assuming a strict-weak order. I.e. the following rule can be considered valid:
if (!(a < b) && !(b < a)) then a == b is true.
That makes your insertion simpler as well.
void add(int value, Tree *t)
{
Node **pp = &(t->root);
while (*pp)
{
if (value < (*pp)->value)
pp = &(*pp)->left;
else if ((*pp)->value < value)
pp = &(*pp)->right;
else { // must be equal.
printf("value already present in BST\n");
return;
}
}
*pp = nodeCreate(value);
t->size++;
}
You're not assigning any of your existing nodes to point to the new node. You walk through the tree, create a new node when you get to the end, but you don't set any existing nodes to point to the new node.
You might want to change your structure to something like:
if ( value < cusor->value )
{
if ( cursor->left )
{
cursor = cursor->left;
}
else
{
cursor->left = newNode(value);
break;
}
}
with similar logic for the right-hand cursor.
The following code snippet is not working right.
void deleteNode(list **start, int pos) {
int currentPosition=0;
list *currentNode;
list *nodToDelete;
currentNode = *start;
if (currentNode == NULL) {
printf("Empty List\n");
} else if (pos == 0 ) {
nodToDelete = *start;
*start = nodToDelete->next;
free(nodToDelete);
} else {
while (currentNode->next != NULL) {
if (currentPosition >= pos -1) {
break;
}
currentPosition++;
currentNode = currentNode->next;
}
if (currentPosition < pos -1 || currentNode->next == NULL) {
printf("No node at given position exists\n");
} else {
nodToDelete = currentNode->next;
currentNode = nodToDelete->next;
free(nodToDelete);
nodToDelete = NULL;
}
}
}
void displayList(list *node) {
if (node == NULL) {
printf("Empty List");
}
while (node != NULL) {
printf("%d\t", node->data);
node = node->next;
}
printf("\n");
}
int main()
{
list *start, *node;
start = NULL;
insertNode(&start, 2);
insertNode(&start, 3);
insertNode(&start, 4);
insertNode(&start, 1);
insertNode(&start, 5);
deleteNode(&start, 3);
displayList(start);
}
When executed the output is
Before Deletion 2 3 4 1 5
After Deletion 2 3 4 0 5
It is supposed to delete 1 but it is inserting 0 at its place.
Here is something that might work --
Replace
currentNode = nodToDelete->next;
with
currentNode->next = nodToDelete->next;
You basically need the node before the nodetodelete to have its next to point to the node that nodetodelete used to point to
Once you've found the node you want to take out of the list, you need to actually take it out. =)
...
nodToDelete = currentNode->next;
currentNode->next = nodToDelete->next;
free(nodToDelete);
...
Besides the problem with currentNode->next = nodToDelete->next; and negative positions you are mixing your ui and your logic. As much as possible you should separate the two.
Sending something to the ui is a way of reporting progress; whether the ui is a command line, a browser or a speaker. Within deleteNode, an empty list or a position that is out of bounds, is not progress. Sequentially both are the same as success - you are done. If you want failure to be to be reported, that should be done where it can lead to a separate sequence...i.e the caller. Also, by mixing in ui, you introduce an unnecessary dependency and failure (what if there's a bug in printf, YOUR function will crash when it doesn't doesn't have to). If you're function returns a defined result, the caller can decide if/how to report that result, including success (your function currently doesn't do so, and the caller has no way telling the difference between sucess or failure).