How find average distance from root to all leaves in a binary tree
Distance means number of edges between the nodes.
The method get the root.
I think add new fields in node.
My code in C:
// A Binary Tree Node
struct Node
{
int data;
Node *left, *right;
};
int findDistance(Node *root)
{
// Base case
if (root == NULL)
return -1;
// Initialize distance
int dist = -1;
if ((root->data != NULL) ||
(dist = findDistance(root->left)) >= 0 + (dist = findDistance(root->right)) >= 0) /2
return dist + 1;
return dist;
}
I expect the following would work, but I have not tested it.
typedef struct
{
int Number; // Number of nodes in tree.
int TotalDepths; // Total of depth of each node.
} NAndTotal;
static NAndTotal FindNumberAndTotalDepth(Node *Root)
{
if (Root == NULL)
return (NAndTotal) { 0, 0 }; // No nodes in empty tree.
// Start an NAndTotal with information about the root node.
NAndTotal A = { 1, 0 }; // Root is 1 node at depth 0.
// Add the left subtree.
NAndTotal B = FindNumberAndTotalDepth(Root->left);
A.Number += B.Number; // Including left subtree adds its nodes.
A.TotalDepth += B.TotalDepth + B.Number; Each of its nodes become one deeper when placed under this node.
// Add the right subtree.
B = FindNumberAndTotalDepth(Root->right);
A.Number += B.Number; // Including right subtree adds its nodes.
A.TotalDepth += B.TotalDepth + B.Number; Each of its nodes become one deeper when placed under this node.
return A;
}
double FindAverage(Node *Root)
{
NAndTotal NT = FindNumberAndTotalDepth(Root);
return (double) NT.TotalDepths / NT.Number;
}
Related
Im looking for iterative non-stack based (due to memory constraints, and minimal refactoring) kd-tree insertion only.
I have an entire kd-tree library working in C, functions (insert ,read, update, delete, knn search, rebalancing) I started to replace all recursive functions with iterative ones.
However, I noticed that my insertion was not working for some test data. Meaning actually the search could not find the inserted nodes when using iterative implementation but all data was found when using recursive implementation, , therefore, the bug is in iterative insert version.
node structure:
typedef struct kd_tree_node
{
struct kd_tree_node* left;
struct kd_tree_node* right;
struct kd_tree_node* parent;
float* dataset;
float distance_to_neighbor;
} kd_tree_node;
Below is an iterative insertion (i included parts directly related. No rebalacing logic, etc...):
void
kd_tree_add_record(kd_tree_node* root, const float data [], int depth,
const int k_dimensions,
const int copying, const float rebuild_threshold) {
/*rebalancing logic is NOT relevant, which I have NOT include, we can just build inefficient tree*/
/* is root empty? */
if (is_empty_node(root, k_dimensions)) {
root = kd_tree_new_node(data, k_dimensions, copying);
/*was the root set before*/
if (is_empty_node(kd_tree_get_root(), k_dimensions)) {
kd_tree_set_root(root);
}
} else {
/*iteratively insert new node*/
current = kd_tree_get_root();
/*while current is NOT null*/
while (!is_empty_node(current, k_dimensions)) {
parent = current;
/* Calculate current dimension (cd) of comparison */
cd = depth % k_dimensions;
/*determine current dimension/*/
/*by using modula operator we can cycle through all dimensions */
/* and decide the left or right subtree*/
median = kd_tree_get_column_median(cd);
//printf("kd_tree_add_record.(), median=%f\n",median);
if (data[cd] < median) {
current = current->left;
} else {
current = current->right;
}
depth++;
}//end while
/*should be inserted left or right of the parent*/
int insert_left = 1;
depth = 0;
if (!is_empty_node(parent,k_dimensions)) {
int c = 0;
for (; c < k_dimensions; c++) {
cd = depth % k_dimensions;
median = kd_tree_get_column_median(cd);
if (parent->dataset[cd] < median) {
} else {
insert_left = 0;
break;
}
depth++;
}
if (insert_left)
{
parent->left = kd_tree_new_node(data, k_dimensions, copying);
}
else
{
parent->right = kd_tree_new_node(data, k_dimensions, copying);
}
}
}//end else
}
I based my iterative kd-tree insert above code, by attempting to follow the iterative binary tree insert C++ code from: (https://www.techiedelight.com/insertion-in-bst/) which can be tested online, see below(note this not my code and its provided as reference):
void insertIterative(Node*& root, int key)
{
// start with root node
Node *curr = root;
// pointer to store parent node of current node
Node *parent = nullptr;
// if tree is empty, create a new node and set root
if (root == nullptr)
{
root = newNode(key);
return;
}
// traverse the tree and find parent node of key
while (curr != nullptr)
{
// update parent node as current node
parent = curr;
// if given key is less than the current node, go to left subtree
// else go to right subtree
if (key < curr->data)
curr = curr->left;
else
curr = curr->right;
}
// construct a new node and assign to appropriate parent pointer
if (key < parent->data)
parent->left = newNode(key);
else
parent->right = newNode(key);
}
Here is my previous kd-tree recursive insertion version, which works:
kd_tree_node *
kd_tree_add_record(kd_tree_node * root,
const float data[], int depth,
const int k_dimensions,
const int copying,
const float rebuild_threshold) {
float median = 0.0;
/* Tree is empty? */
if (NULL == root || NULL == root -> dataset || is_empty_node(root, k_dimensions)) {
root = kd_tree_new_node(data, k_dimensions, copying);
//update the root globally
if (kd_tree_get_root() == NULL) {
kd_tree_set_root(root);
}
} else {
/* Calculate current dimension (cd) of comparison */
size_t cd = depth % k_dimensions;
/*determine current dimension/*/
/*by using modula operator we can cycle through all dimensions */
/* and decide the left or right subtree*/
median = kd_tree_get_column_median(cd);
if (data[cd] < median) {
root -> left = kd_tree_add_record(root -> left, data, depth + 1,
k_dimensions,
copying, rebuild_threshold);
} else {
root -> right = kd_tree_add_record(root -> right, data, depth + 1,
k_dimensions,
copying, rebuild_threshold);
}
} //end else
return root;
}
current test results:
-53.148998,0.000000,9.000000 Found
7.999700,0.069812,8.000000 Found
7.998780,0.139619,8.000000 Found
7.997260,0.209416,8.000000 Not Found!
7.995130,0.279196,8.000000 Not Found!
7.992390,0.348955,8.000000 Not Found!
8.987670,0.471024,9.000000 Found
8.983210,0.549437,9.000000 Found
7.980510,0.558052,8.000000 Not Found!
3.000000,3.000000,3.000000 Found
4.000000,4.000000,4.000000 Found
5.000000,5.000000,5.000000 Found!
100.000000,100.000000,100.000000 Found
How can I extend the iterative non-stack binary insert algorithm to kd-trees?
Really appreciated!
I'm attempting to write an implementation of a red-black tree for my own learning and I've been staring at this for a few days now.
Could anyone help me figure out how I can get the double rotation cases to work correctly? If you spot anything else that sucks while you're looking through the snippets, feel free to make me feel like an idiot.
Your help is appreciated.
Rebalancing Function
int impl_rbtree_rebalance (xs_rbtree_node *node)
{
check_mem(node);
xs_rbtree_node *p = node->parent;
if (!p) return 0;
if (p->color == BLACK) return 0;
xs_rbtree_node *gp = p->parent;
if (!gp) return 0;
xs_rbtree_node *uncle;
int is_parent_left_child;
/* check if parent is left or right child */
if (p == gp->left) {
uncle = gp->right;
is_parent_left_child = 1;
} else {
uncle = gp->left;
is_parent_left_child = 0;
}
if (uncle && uncle->color == RED) {
p->color = uncle->color = BLACK;
gp->color = RED;
} else { /* uncle is black */
if (gp->parent == NULL) return 0;
if (node == p->left) {
if (is_parent_left_child == 0) {
/* Double rotation logic */
} else {/* parent is left child */
gp->color = RED;
gp->left->color = BLACK;
impl_rbtree_rr(&gp);
}
} else { /* node is right child */
if (is_parent_left_child == 1) {
/* Double rotation logic */
} else { /* parent is right child */
gp->color = RED;
gp->right->color = BLACK;
impl_rbtree_rl(&gp);
}
}
}
return 0;
}
Relevant Functions
xs_rbtree_node *impl_rbtree_node_alloc (xs_rbtree_node *parent, void *val)
{
xs_rbtree_node *n = malloc(sizeof(xs_rbtree_node));
n->parent = parent;
n->val = val;
n->left = n->right = NULL;
n->color = (parent == NULL) ? BLACK : RED;
return n;
}
void rbtree_insert (xs_rbtree_ *tree, void *val)
{
check_mem(tree);
check_mem(val);
tree->root = impl_rbtree_insert(tree->cmp, NULL, tree->root, val);
tree->root->color = BLACK;
}
xs_rbtree_node *impl_rbtree_insert (xs_tree_cmp cmp, xs_rbtree_node *parent, xs_rbtree_node *node, void *val)
{
check_mem(cmp);
check_mem(val);
if (!node) {
node = impl_rbtree_node_alloc(parent, val);
} else if (cmp(node->val, val) < 0) {
/* node->val < val */
check_mem(node);
node->right = impl_rbtree_insert(cmp, node, node->right, val);
impl_rbtree_rebalance(node->right);
} else if (cmp(node->val, val) > 0) {
/* node->val > val */
check_mem(node);
node->left = impl_rbtree_insert(cmp, node, node->left, val);
impl_rbtree_rebalance(node->left);
}
/* ignoring values that are equal */
return node;
}
Rotation Functions
#include <xs/base/bstree.h>
void impl_tree_rr(xs_tree_node **node)
{
check_mem(*node);
check_mem((*node)->left);
xs_tree_node *k1, *k2;
k2 = *node;
k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k1->parent = k2->parent;
k2->parent = k1;
*node = k1;
}
void impl_tree_rl(xs_tree_node **node)
{
check_mem(*node);
check_mem((*node)->right);
xs_tree_node *k1, *k2;
k2 = *node;
k1 = k2->right;
k2->right = k1->left;
k1->left = k2;
k1->parent = k2->parent;
k2->parent = k1;
*node = k1;
}
void impl_tree_drr(xs_tree_node **node)
{
check_mem(*node);
impl_tree_rl(&((*node)->left));
impl_tree_rr(node);
}
void impl_tree_drl(xs_tree_node **node)
{
check_mem(*node);
impl_tree_rr(&((*node)->right));
impl_tree_rl(node);
}
RBT Definitions
typedef struct xs_rbtree_node xs_rbtree_node;
typedef struct xs_rbtree_ xs_rbtree_;
typedef enum { RED, BLACK } impl_rbtree_color;
struct xs_rbtree_node {
xs_rbtree_node *left;
xs_rbtree_node *right;
xs_rbtree_node *parent;
void *val;
impl_rbtree_color color;
};
struct xs_rbtree_ {
xs_rbtree_node *root;
xs_tree_cmp cmp;
};
Double rotation is kind of tricky in Red Black trees when compared to AVL trees, the reason being the existence of parent pointers which exist in RB trees.
While we rotate the trees we need to adjust the parent pointers too.
I will to demonstrate it with an example. The tree below is the initial tree
20
/ \
10 30
/ \
3 15
/ \
12 18
And here goes the right rotated one
10
/ \
3 20
/ \
15 30
/ \
12 18
We observe 2 things there.
1. The root got changed.
2. The parent pointers for 3 nodes got changed ( 10, 20, 15 ) ie. for new root, old root and right child of new root. This will be true for
all right rotation cases. This is to make sure that that, the in order
traversal remains intact after rotation happens.
Now see how we rotate step by step.
public Node rotateRight() {
if(root.left == null) {
System.out.println("Cannot be rotated Right");
} else {
Node newRoot = root.left; // Assign new root.
Node orphaned = newRoot.right; // Store ref to the right child of new root.
newRoot.parent = root.parent; // new root parent point to old root parent.
root.parent = newRoot; // new root becomes parent of old root.
newRoot.right = root; // old root becomes right child of new root
root.left = orphaned;
if (orphaned != null) {
orphaned.parent = root;
}
root = newRoot;
}
return root;
}
Try doing this on paper couple of times, then it will look simpler.
Hope this helps.
Coming back to RB Trees. The above implementation will be applied to both the rotations we do in the balancing process. ( Let us take right right case)
When we have 3 generations of nodes, a grandfather, a father and a
child which got inserted.
1. When we have RR or LL config, do not swap colors
2. With RL and LR, we rotate the grandfather we swap the colour of grandpa and father, but when rotating the parent we do not try to swap
colours. Intent is just to bring them to RR or LL configs.
a. We need to see if the grandpa is right or left child of its
parent and assign the root accordingly.
b. If the grandpa has no parent means we are doing rotation at the level of tree's root, then we reassign the root of the tree.
Snippet for my implementation of RB tree.
temp is the new node which is added.
// if new node is the right child AND parent is right child
else if(temp.parent.right == temp && grandPa!=null && grandPa.right == temp.parent) {
// If becomes a right-right case
Boolean isLeft = isLeftChild(grandPa);
if(isLeft == null) {
// Grandpa has no parent, reassign root.
root = rotateLeft(grandPa,true);
}
else if(isLeft) {
grandPa.parent.left = rotateLeft(grandPa,true);
} else {
grandPa.parent.right = rotateLeft(grandPa,true);
}
}
I am trying to write this function:
struct treeNode *pruneTree(struct treeNode *root, int depth);
Which given a tree like:
1 level 0
/ \
2 3 level 1
/ \ \
4 5 6 level 2
/ \
7 8 level 3
If depth = 1 then create a tree with depth = 1 and cut everything after so the result should be:
1
/ \
2 3 // tree with depth = 1
I know how to write a function that prunes the leaves and I am trying to adapt it to prune at any level:
int isLeaf (struct treeNode * treeNode) {
return (treeNode->left == NULL) && (treeNode->right == NULL);
}
void removeLeaves(struct treeNode * root) {
if (root->left != NULL) {
if (isLeaf (root->left)) {
free(root->left);
}
else {
removeLeaves(root->left);
}
}
if (root->right != NULL) {
if (isLeaf (root->right)) {
free(root->right);
}
else {
removeLeaves(root->right);
}
}
}
What is a good strategy to do this? My approach is to replace the isLeaf function with a isAfterDepth function and using a helper function that calculates the depth, but this doesn't seem efficient. What is a more elegant way to do it?
Copying the tree
If you intend to make a copy of the tree that is pruned at a certain level, you can simply use recursion and at each recursive call decrease the depth parameter with one, if the depth results in 0, you simply do no longer recursively copy the children.
struct treeNode *pruneTree(struct treeNode *root, int depth) { //version where the tree is copied
if(root == NULL || depth < 0) {
return NULL;
} else {
treeNode *copyRoot = (treeNode*) malloc(sizeof(treeNode));
copyRoot->value = root->value;
copyRoot->left = pruneTree(root->left,depth-1);
copyRoot->right = pruneTree(root->right,depth-1);
return copyRoot;
}
}
The code works as follows: if the given root pointer is NULL or th depth is less than zero, NULL is returned, because either we call this with the child of a leaf or the depth constraint has been reached.
If that is not the case, we make a copy of the current node: we allocate a new treeNode object, copy the value of the original node (assuming this is called value), and perform a recursive call to copy the left and right children.
Altering the tree
You can also alter the current tree. In that case, you better first define a function to remove a subtree and all its descendants:
void prune(struct treeNode * root) {
if(root != NULL) {
if (root->left != NULL) {
prune(root->left);
}
if (root->right != NULL) {
prune(root->right);
}
free(root);
}
}
Now we simply need to define a method that will prune only at a certain level:
struct treeNode *pruneTree(struct treeNode *root, int depth) { //version where the tree is altered
if(root != NULL) {
if(depth <= 0) {
prune(root->left);
root->left = NULL;
prune(root->right);
root->right = NULL;
} else {
pruneTree(root->left,depth-1);
pruneTree(root->right,depth-1);
}
}
return root;
}
Alright so there is a lot of code here, but I thought it was best in case something wasn't immediately evident in my logic.
My issue starts with the height, and my calculated balancing factor. I have looked up a countless amount of AVL-tree algorithms, and done a lot of rough work on paper to try to figure out the best way to tackle the balancing aspect of this beast of a tree. Here is what I've gotton:
typedef struct node {
char* key;
struct node *left;
struct node *right;
int height;
int frequency;
}node;
int max(int a, int b)
{
if(a > b)
{
return a;
}
else
return b;
}
// A utility function to get height of the tree
int height(node* N)
{
if(N==NULL)
return -1;
return N->height;
}
// A utility function to get maximum of two integers
int avlHeight(node* N) {
if(N == NULL)
return -1;
else
return max(height(N->left), height(N->right))+1;
}
node *rightRotate(node *y) //preform a right AVL rotation
{
node *x = y->left;
node *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Return new root
return x;
}
// A utility function to left rotate subtree rooted with x
// See the diagram given above.
node *leftRotate(node *x) //perform a left AVL rotation
{
node *y = x->right;
node *T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right))+1;
y->height = max(height(y->left), height(y->right))+1;
// Return new root
return y;
}
// Get Balance factor of node N
int getBalance(node *N)//get the balance factor
{
if (N == NULL)
return -1;
return height(N->left) - height(N->right);
}
node* insert(node* node, char* key)//function to insert new nodes to the tree
{
if (node == NULL)
return (newNode(key));
// printf("%s",key);
if(strcmp(node->key, key)==0)
{
node->frequency = node->frequency+1;
return node;
}
if (strcmp(key, node->key) < 0)
node->left = insert(node->left, key);
else
node->right = insert(node->right, key);
/* 2. Update height of this ancestor node */
node->height = max(height(node->left), height(node->right)) + 1;
/* 3. Get the balance factor of this ancestor node to check whether
this node became unbalanced */
int balance = getBalance(node);
printf("%d\n",balance);
// If this node becomes unbalanced, then there are 4 cases
// Left Left Case
if (balance > 1 && strcmp(key, node->left->key)<0) {
return rightRotate(node);
}
// Right Right Case
if (balance < -1 && strcmp(key, node->right->key)>0)
return leftRotate(node);
// Left Right Case
if (balance > 1 && strcmp(key, node->left->key)>0) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// Right Left Case
if (balance < -1 && strcmp(key, node->right->key)<0) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
/* return the (unchanged) node pointer */
return node;
}
I̶ ̶d̶o̶ ̶n̶o̶t̶ ̶g̶e̶t̶ ̶a̶n̶y̶ ̶s̶e̶g̶-̶f̶a̶u̶l̶t̶s̶,̶ ̶e̶r̶r̶o̶r̶s̶,̶ ̶o̶r̶ ̶w̶a̶r̶n̶i̶n̶g̶s̶.̶ The program segfaults when the balance factor is 2. I am parsing roughly 44k lines of keys into this tree, and any multiples are being added to the structs frequency counter. The only thing that is not correct with my tree is that the frequency is off by 1-3 elements for any given node, and the heights are not what they should be for all elements.
I was pretty sure when I was debugging it had to do with my balancing algorithm, because for one my heights were completely off (got as high as 7 I believe) and about 70% of my nodes had the correct amount of counts (frequency).
My big question: What is wrong with my balancing logic and/or rotation logic?
Is my entire code wrong, or am I at least on the right track?
**after updating code
for some god forsaken reason when I take out the node I segfault at, the entire program works, but gives me the wrong frequencies still :/
So quite literally 1 element/node makes this segfault, yet it is still wrong...
example input->
wrn69 flr830 flr662 flr830 flr830
flr231 flr2166 flr1854 wrn69 wrn69
flr231 flr2166
wrn69
flr830
I think there are multiple errors in my code for deleting a node from a BST. I just can't figure out what! Here's my code. Thanks in advance!
void del(int val){
help = root;
f = help;
while (help){
if(help->data==val) break;
f = help;
if (val > help-> data) help = help->right;
else help = help->left;
} if(help->data != val) printf("\nElement not found!");
else{
printf("Element found!");
target = help;
if(val>f->data){
if(target->right && !target->left) {f->right = target->right; f = target->right;}
else {f->right = target->left; f = target->left;}
} else{
if(target->right && !target->left) {f->left = target->right; f = target->right;}
else {f->left = target->left; f = target->left;}
}
while(help ->right) help = help->right;
if(help->left) help = help->left;
f->right = help;
free(target);
}
}
One error that I spot is that if one were to delete the left node in the tree, then the last few lines might not work since they are not symmetric. So, let us say, the tree has root as 6 and left-child as 4 and right-child as 8. Now, you want to delete 4. So, after you have found the node in the first while clause, you would hit the else clause of "if (val > f->data){". At this point, f would point to 6, target and help would point to 4. Now, you are setting the left of f to right of target, so left of 6 would point to NULL and f itself would point to NULL. So, far so good! But, once you get into the while loop, since help has no right node, help would continue to point to 6. In the end, you make the right node of f (btw, f is already NULL at this point) to help and you would actually end up crashing!
while (help->right)
help = help->right;
if (help->left)
help = help->left;
f->right = help;
Another error is that you do not update the root pointer, incase you end up deleting the root node.
One simpler approach would be to divide this into three cases. I am providing code for all the three cases. Use a sample tree for each of these three cases and then debug/test it.
First, if the found node (which your file while loop is doing) has no child nodes, then delete it and set its parent to NULL and you are done. Here is a rough-first cut of the first case:
/* If the node has no children */
if (!help->left && !help->right) {
printf("Deleting a leaf node \n");
f = help->parent;
if (f) {
if (value > f->value)
f->right = NULL;
else
f->left = NULL;
}
/* If deleting the root itself */
if (f->value == root) {
root = NULL;
}
free(help);
return 0;
}
Second, if the found node has only child (left or right), then splice it out and the child of the found node becomes hte child of the parent node. Here is the second case:
/* If the node has only one child node */
if ((help->left && !help->right)
|| (!help->left && help->right)) {
printf("Deleting a node with only one child \n");
f = help->parent;
if (help->left) {
child_node = help->left;
} else {
child_node = help->right;
}
if (f) {
if (value > f->value) {
f->right = child_node;
} else {
f->left = child_node;
}
} else {
/* This must be the root */
root = child_node;
}
free(help);
return 0;
}
The third case is tricky -- here the found node has two child nodes. In this case, you need to find the successor of the node and then replace the value of the found node with the successor node and then delete the successor node. Here is the third case:
/* If the node has both children */
if (help->left && help->right) {
successor_found = find_successor(help, help->data);
printf("Deleting a node with both children \n");
if (successor_found) {
successor_value = successor_found->value;
del(successor_found->value);
help->value = successor_value;
}
return 0;
}
And, here is the code to find successor:
binary_node_t *node find_successor(binary_node_t *node, int value) {
binary_node_t *node_found;
if (!node) {return NULL; }
node_found = node;
old_data = node->data;
/* If the node has a right sub-tree, get the min from the right sub-tree */
if (node->right != NULL) {
node = node->right;
while (node) {
node_found = node;
node = node->left;
}
return node_found;
}
/* If no right sub-tree, get the min from one of its ancestors */
while (node && node->data <= old_data) {
node = node->parent;
}
return (node);
}
typedef struct xxx {
struct xxx *left;
struct xxx *right;
int data;
} ;
#define NULL (void*)0
#define FREE(p) (void)(p)
void treeDeleteNode1 (struct xxx **tree, int data)
{
struct xxx *del,*sub;
/* Find the place where node should be */
for ( ; del = *tree; tree = (data < del->data) ? &del->left : &del->right ) {
if (del->data == data) break;
}
/* not found: nothing to do */
if ( !*tree) return;
/* When we get here, `*tree` points to the pointer that points to the node_to_be_deleted
** If any of its subtrees is NULL, the other will become the new root
** ,replacing the deleted node..
*/
if ( !del->left) { *tree = del->right; FREE(del); return; }
if ( !del->right) { *tree = del->left; FREE(del); return; }
/* Both subtrees non-empty:
** Pick one (the left) subchain , save it, and set it to NULL */
sub = del->left;
del->left = NULL;
/* Find leftmost subtree of right subtree of 'tree' */
for (tree = &del->right; *tree; tree = &(*tree)->left) {;}
/* and put the remainder there */
*tree = sub;
FREE(del);
}
To be called like:
...
struct xxx *root;
...
treeDeleteNode1( &root, 42);
...