I am practicing binary search trees and i have to answer a problem:
A tree struct is given as
struct tree{
int key;
int lcnt;
struct tree *lc;
struct tree *rc;
};
where lcnt is an integer holding the number of the nodes at the left subtree of each node. The problem is to split the tree in half updating every time the lcnt with the valid value. The split algorith must take O(h) time where h is the tree's hight. I found the solution down below and it works for the most trees. But consider now this tree
170
/
45
\
30
the result will be: tree1: 170, tree2: 45.
I have no idea how to fix it because if i try something like "dont split if the node is a leaf" or something then i have problems with other trees. The split function takes the parameter root which is the root of the primary tree, an integer which is the trees lenght/2 and it returns the 2 new trees. The one with return and the other by reference using a third parameter double pointer tree. I am also using updt function and some calculations to update the lcnt at every split.
the code is here:
struct tree* split(struct tree *root, struct tree **new_tree, int collect){
struct tree *new_root_1, *new_root_2, *link1=NULL, *link2=NULL;
struct tree *current=root, *prev=NULL, *temp=NULL;
if(!root)
return NULL; //empty tree
int collected=0, created_root1=0, created_root2=0;
int decrease;
while(current!=NULL && collected<collect){
if(collected+current->lcnt+1<=collect){
// there is space for the left subtree so take it all and move to the right
collected=collected+current->lcnt+1; //update the number of the collected nodes
if(!created_root1){
//create the root for the one tree
created_root1=1;
new_root_1=current;
link1=current;
}else{
link1->rc=current;
link1=current;
}
if(!created_root2 && collect==collected)
//in case the tree must be splited in half
new_root_2=current->rc;
prev=current;
current=current->rc;
//break the node link
prev->rc=NULL;
}else{
// there is no space for the left subtree so traverse it until it becomes small enough
if(!created_root2){
//create the root for the second tree
created_root2=1;
new_root_2=current;
link2=current;
}else{
link2->lc=current;
// at every link at left the count_total_tasks will help to update the lcnt of the
parent node
temp=new_root_2;
while(temp!=NULL){
temp->lcnt=count_total_tasks(temp->lc);
temp=temp->lc;
}
link2=current;
}
prev=current;
current=current->lc;
//break the node link
prev->lc=NULL;
//update the lcnt
decrease=prev->lcnt;
updt(new_root_2, decrease);
}
}
*new_tree=new_root_2;
return new_root_1;
}
And this is the updt function:
void updt(struct tree* root, int decrease){
struct tree *temp;
temp=root;
while(temp!=NULL){
temp->lcnt=temp->lcnt-decrease;
temp=temp->lc;
}
}
Your test case,
170
/
45
\
30
is not a valid binary search tree.
Related
How can I insert data to huffman tree in c?
huffman_tree *huffman_node_create(char data, unsigned int frequency)
{
huffman_tree *node = malloc(sizeof(huffman_tree));
node->data = data;
node->frequency = frequency;
node->left = NULL;
node->right = NULL;
return node;
}
I write this to create Huffman tree. But I do not know how can I add the frequency the tree, how can I know the number should be right or left?
and:
typedef struct huffman_tree{
char c;
int freq; //unsigned?
struct huffman_tree *left; // 0 (left)
struct huffman_tree *right; // 1 (right)
}huffman_tree;
It doesn't matter if they're right or left, actually.
The way to construct a Huffman tree is to keep selecting the two lowest frequencies and combining them into a tree node so that one becomes the left child, the other the right, and the combined frequency is the sum of the two frequencies. This combined node is put in the table, replacing its two children. The tree gets built gradually as previously combined nodes get paired with others. This process continues until all frequencies have been combined into a single tree.
Maybe take a look at this? https://www.geeksforgeeks.org/huffman-coding-greedy-algo-3/
In general Numbers go to the left if they are smaller and to the right if they are larger than the previous node.
struct cnode
{
int info;
struct cnode *next;
struct cnode *previous;
};
typedef struct cnode cnode;
pre-made DOUBLY LINKED LIST: 1<->2<->3<->4<->5<->6<->7
So I'm trying to make a recursive function that grabs the mid of the doubly linked list (root = 4) and convert it into a the remaining into a binary tree. I'm still new to recursion so an explanation along with code would be GREATLY appreciated!
EX. 4
/ \
2 6
/ \ / \
1 3 5 7
This is the code I have thus far (which isn't much due to difficulties with recursion)
void *convert(cnode *head){
if(head == NULL)
return;
int count = 0;
cnode *tempHead = head;
while(tempHead != NULL){
count++;
tempHead = tempHead->next;
}
int move = (count/2) + (count%2);
int i;
for(i=1; i<move; i++){
head = head->next;
}
}
Pretty much just sets the head pointer to the mid info (4)
I think I understand; you're making a balanced binary tree from cnodes with the previous and next pointers being reused for the left and right sub-trees.
... so that's your algorithm.
Find the middle node of the binary tree (which you've already done).
Turn the left half into a binary tree. The left half is the original head, with the last element (middle->previous) now having a next pointer of NULL.
Link this left half to middle->previous (hijacked as the left sub-tree).
Turn the right half into a binary tree; this is headed by middle->next. Make it the new value of middle->next.
You have to keep the original head as the pointer to the left sub-tree.
You'll want your routine to return the binary tree's root, so the previous call can link it into the level above.
You still have to pick a termination condition, such as the head pointer being NULL.
Does that get you moving to a solution?
I hope this code will help you. call the DLL2BT method with head of the doubly linked list which return the root node of the tree created.
class box
{
int data;
box left=null,right=null;
box(int a)
{
data=a;
}
}
public static box DLL2BT(box head)// head = linked list head
{
if(head!=null)
{
box node=null;
try
{
node = findMid(head);
node.left.right=null;
node.left=DLL2BT(head);
node.right.left=null;
node.right=DLL2BT(node.right);
}
catch( Exception e){ }
return node;
}
return null;
}
public static box findMid(box head)
{
box slow=head,fast=head.right;
try
{
while(fast!=null)
{
slow=slow.right;
fast=fast.right.right;
}
}
catch(Exception e){ }
return slow;
}
Firstly, You are trying to convert DLL to binary tree assuming the DLL is given as in-order of the binary tree you have to make. Note that there isn't a unique tree you can make from only inorder traversal.Even if you have to make BST, you can't make it with only inorder traversal. What I actually think you are trying to do is to convert it into a balanced BST. Even though, it will also not be unique.
Here's the algorithm..
1) Get the Middle of the linked list and make it root.
2) Recursively do same for left half and right half.
a) Get the middle of left half and make it left child of the root
created in step 1.
b) Get the middle of right half and make it right child of the
root created in step 1.
Time complexity: O(nLogn) where n is the number of nodes in Linked List.
Although,it can be solved in O(n) if you insert nodes in BST in the same order as the appear in Doubly Linked List.
Here is a simple binary tree in c, but it seems not balance, how to make it balance?
Code:
/**
* binary_tree impl
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct _tnode _tnode;
typedef struct _bin_tree _bin_tree;
struct _tnode {
int data;
_tnode *parent;
_tnode *left;
_tnode *right;
};
_tnode *new_node(int data) {
_tnode *node = (_tnode*)malloc(sizeof(_tnode));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
_tnode *add(_tnode *top, int new_data, int (*cmpf)(int, int)) {
if(top == NULL) {
top = new_node(new_data);
} else if(cmpf(top->data, new_data)<=0) {
if(top->left == NULL)
top->left = new_node(new_data);
else
add(top->left, new_data, cmpf);
} else {
if(top->right == NULL)
top->right = new_node(new_data);
else
add(top->right, new_data, cmpf);
}
return top;
}
int cmp_int(int n1, int n2) {
return n1 - n2;
}
void print_tree(_tnode *top) {
if(top->left) print_tree(top->left);
printf("%d\n",top->data);
if(top->right) print_tree(top->right);
}
int main(int argc, char * argv[]) {
int i = 0;
_tnode *top = NULL;
int arr[] = {6,1,9,3,5,0,2,7};
int count = sizeof(arr) / sizeof(arr[0]);
for(i=0; i<count; i++) {
top = add(top, arr[i], cmp_int);
printf("add: %d\n", arr[i]);
}
print_tree(top);
return 0;
}
The basic idea is as follows.
For insertions, you first insert your new node at a leaf exactly as you would for a non-balanced tree.
Then you work your way up the tree towards the root, making sure that, for each node, the difference in height between the left and right sub-trees is never more than one.
If it is, you "rotate" nodes so that the difference is one or less. For example, consider the following tree, which was balanced before you added 32 but now isn't:
128
/
64
/
32
The depth differential at the 32 node is zero as both sub-trees have a depth of zero.
The depth differential at the 64 node is one as the left sub-tree has a depth of one and the right sub-tree has a depth of zero.
The depth differential at the 128 node is two as the left sub-tree has a depth of two and the right sub-tree has a depth of zero. So a rotation through that node needs to occur. This can be done by pushing the 128 down to the right sub-tree and bringing up the 64:
64
/ \
32 128
and you once again have balance.
The direction of rotation depends, of course, on whether the height is too much on the left or the right.
Deletion is a little more tricky since you're not necessarily working at a leaf node like you are with insertion. It gets a little complex there since it depends on whether the node has no children (is a leaf), one child, or two children.
1/ For a leaf node, you can just delete it, then start re-balancing at the parent of that leaf.
2/ For a one-child node, you can just copy the child information (data and links) to replace the one you want to delete, then delete the child and start re-balancing where the child information now is.
3/ For a two-child node, the idea is to find its immediate successor (by first going to the right child then continuously going to the left child until there are no more left children). You could also find its immediate predecessor (left then continuously right) which works just as well.
Then you swap the data in the node you want to delete with the data in the successor (or predecessor), then re-apply this rule until the node you want to delete is a leaf node. Then just delete that leaf node, using the exact same rules as per (1) above.
This swapping trick is perfectly valid since, even though the swap puts two adjacent items temporarily out of sequence, the fact that you're deleting one of them (2 in this case) auto-magically fixes things up:
2 3 3
/ \ --> / \ --> /
1 3 1 2 1
===== ===== =====
1,2,3 1,3,2 1,3
I am new to C and I am learning functions and pointers. I have to print Binary search tree in the requisite format below in the t_print method and I would be really grateful some could guide me how to go about it.
I have this code till now:
typedef struct tree {
void* data;
struct tree* left;
struct tree* right;
} Tree;
/*set the data on the tree node */
void t_set_data(Tree* t, void* data) {
t->data = data;}
/*let l be the left node of tree *t */
void t_set_left(Tree* t, Tree* l){
t->left = l;}
/*let r be the left node of tree *t */
void t_set_right(Tree* t, Tree* r){
t->right = r;}
/* simply return left node of the tree */
Tree* t_left(Tree* t){
return t-> left;}
/* simply return right node of the tree */
Tree* t_right(Tree* t){
return t-> right;}
/* simply return the data of the tree */
void* t_data(Tree* t){
return t->data;}
/* make the node of the tree and allocate space for it*/
Tree* t_make(){
Tree *t = (Tree*)malloc(sizeof(tree));
t->left=NULL;
t->right = NULL;
t-> data = NULL;
return t;
}
/*
print the whole tree in the following format
Root is printed with zero trailing spaces to the left
Every node/subtree is printed with one additional space
Below is an example for a tree with depth 2:
Root
<space>Left-Child
<space><space>Left-Left-Child
<space><space>Left-Right-Child
<space>Right-Child
.... and so on ...
Use (void(* p))(function pointer) to print.
*/
void t_print( Tree* t ,int space, void(* p)(void*) ){
}
It depends on the order in which you want the data printed, but for a BST, 'in order' is appropriate (as opposed to pre-order or post-order).
To print a tree 'in order', the function does:
If the current node is not null
print the left sub-tree in order
print the current node
print the right sub-tree in order
The 'print the xxx sub-tree in order' operations are recursive calls to the 'print in order' function with the left or right pointer.
The algorithm for pre-order is:
If the current node is not null
print the current node
print the left sub-tree in pre-order
print the right sub-tree in pre-order
The algorithm for post-order is:
If the current node is not null
print the left sub-tree in post-order
print the right sub-tree in post-order
print the current node
And it really is that simple.
Well, nearly that simple...
If you want to bracket the data or otherwise make it possible to identify the tree structure, you have to work a little harder. You also typically end up with a cover function that adds a prefix (tag identifying the output) and a suffix (maybe just a newline); this is not part of the recursive printing, usually. But the core of the algorithm is as simple as described.
I have an AVL Tree. Each node looks like this:
typedef struct {
Node *parent; // the parent node
Node *left; // the node left of this node
Node *right; // the node right of this node
int height; // the height of this node
void *value; // payload
} Node;
Is it possible to iterate over an AVL tree with these nodes in O(1) space, without recursion, if yes, how?
If not, a solution with sub-O(n) space or iff really necessary O(N) space is appreciated as well.
With iterating over the tree I mean I want to visit each node once, and if possible in order (from the mostleft to the mostright node).
If you store the last node you have visited, you can derive the next node to visit in an iterator.
If the last node was your parent, go down the left subtree.
If the last node was your left subtree, go down the right subtree.
If the last node was your right subtree, go to your parent.
This algorithm gives you a traversal in O(1) for the tree. You need to flesh it out a little for the leaves and decide what kind of iterator (pre/in/post-order) you want to decide where the iterator should and wait for incrementation.
It is possible to get the next in-order node given a pointer to some node, as long as you keep parent pointers. This can be used to iterate the tree, starting with the leftmost node. From my implementation of AVL tree:
BAVLNode * BAVL_GetNext (const BAVL *o, BAVLNode *n)
{
if (n->link[1]) {
n = n->link[1];
while (n->link[0]) {
n = n->link[0];
}
} else {
while (n->parent && n == n->parent->link[1]) {
n = n->parent;
}
n = n->parent;
}
return n;
}
To get the leftmost node:
BAVLNode * BAVL_GetFirst (const BAVL *o)
{
if (!o->root) {
return NULL;
}
BAVLNode *n = o->root;
while (n->link[0]) {
n = n->link[0];
}
return n;
}
Here, node->link[0] and node->link[1] are the left and right child of the node, respectively, and node->parent is the pointer to the parent node (or NULL for root).
A single GetNext() operation has O(logn) time complexity. However, when used to iterate the entire tree, you get O(n) amortized time complexity.
"Datastructures and their algorithms" by Harry Lewis and Larry Denenberg describe link inversion traversal for constant space traversal of a binary tree. For this you do not need parent pointer at each node. The traversal uses the existing pointers in the tree to store path for back tracking. 2-3 additional node references are needed. Plus a bit on each node to keep track of traversal direction (up or down) as we move down. In my implementation of this algorithms from the book, profiling shows that this traversal has far less memory / processor time. An implementation in java (c would be faster i guess) is here.