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