We consider a variant of binary search trees in which $left(n) ≤ n < right(n)$ and this for any node $n$ of the tree.
Given two binary search trees $A$ and $B$, we are interested in removing from the tree $B$ all the elements that are common to $A$.
Difficulty level
This exercise is mostly suitable for students
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct Tree Tree;
struct Tree
{
Tree * left, * right;
int element;
};
/*
typedef struct node
{
int data;
struct node *left, *right;
} *BST;
*/
typedef Tree *BST;
Tree *make_empty(Tree *t)
{
if (t != NULL)
{
make_empty(t->left);
make_empty(t->right);
free(t);
}
return NULL;
}
Tree *find_min(Tree *t)
{
if (t == NULL)
{
return NULL;
}
else if (t->left == NULL)
{
return t;
}
else
{
return find_min(t->left);
}
}
Tree *find_max(Tree *t)
{
if (t == NULL)
{
return NULL;
}
else if (t->right == NULL)
{
return t;
}
else
{
return find_max(t->right);
}
}
Tree *find(int elem, Tree *t)
{
if (t == NULL)
{
return NULL;
}
if (elem < t->element)
{
return find(elem, t->left);
}
else if (elem > t->element)
{
return find(elem, t->right);
}
else
{
return t;
}
}
//Insert i into the tree t, duplicate will be discarded
//Return a pointer to the resulting tree.
Tree * insert(int value, Tree * t)
{
Tree * new_node;
if (t == NULL)
{
new_node = (Tree *) malloc (sizeof (Tree));
if (new_node == NULL)
{
return t;
}
new_node->element = value;
new_node->left = new_node->right = NULL;
return new_node;
}
if (value < t->element)
{
t->left = insert(value, t->left);
}
else if (value > t->element)
{
t->right = insert(value, t->right);
}
else
{
//duplicate, ignore it
return t;
}
return t;
}
Tree * delete(int value, Tree * t)
{
//Deletes node from the tree
// Return a pointer to the resulting tree
Tree * x;
Tree *tmp_cell;
if (t==NULL) return NULL;
if (value < t->element)
{
t->left = delete(value, t->left);
}
else if (value > t->element)
{
t->right = delete(value, t->right);
}
else if (t->left && t->right)
{
tmp_cell = find_min(t->right);
t->element = tmp_cell->element;
t->right = delete(t->element, t->right);
}
else
{
tmp_cell = t;
if (t->left == NULL)
t = t->right;
else if (t->right == NULL)
t = t->left;
free(tmp_cell);
}
return t;
}
//printing tree in ascii
typedef struct asciinode_struct asciinode;
struct asciinode_struct
{
asciinode * left, * right;
//length of the edge from this node to its children
int edge_length;
int height;
int lablen;
//-1=I am left, 0=I am root, 1=right
int parent_dir;
//max supported unit32 in dec, 10 digits max
char label[11];
};
#define MAX_HEIGHT 1000
int lprofile[MAX_HEIGHT];
int rprofile[MAX_HEIGHT];
#define INFINITY (1<<20)
//adjust gap between left and right nodes
int gap = 3;
//used for printing next node in the same level,
//this is the x coordinate of the next char printed
int print_next;
int MIN (int X, int Y)
{
return ((X) < (Y)) ? (X) : (Y);
}
int MAX (int X, int Y)
{
return ((X) > (Y)) ? (X) : (Y);
}
asciinode * build_ascii_tree_recursive(Tree * t)
{
asciinode * node;
if (t == NULL) return NULL;
node = malloc(sizeof(asciinode));
node->left = build_ascii_tree_recursive(t->left);
node->right = build_ascii_tree_recursive(t->right);
if (node->left != NULL)
{
node->left->parent_dir = -1;
}
if (node->right != NULL)
{
node->right->parent_dir = 1;
}
sprintf(node->label, "%d", t->element);
node->lablen = strlen(node->label);
return node;
}
//Copy the tree into the ascii node structre
asciinode * build_ascii_tree(Tree * t)
{
asciinode *node;
if (t == NULL) return NULL;
node = build_ascii_tree_recursive(t);
node->parent_dir = 0;
return node;
}
//Free all the nodes of the given tree
void free_ascii_tree(asciinode *node)
{
if (node == NULL) return;
free_ascii_tree(node->left);
free_ascii_tree(node->right);
free(node);
}
//The following function fills in the lprofile array for the given tree.
//It assumes that the center of the label of the root of this tree
//is located at a position (x,y). It assumes that the edge_length
//fields have been computed for this tree.
void compute_lprofile(asciinode *node, int x, int y)
{
int i, isleft;
if (node == NULL) return;
isleft = (node->parent_dir == -1);
lprofile[y] = MIN(lprofile[y], x-((node->lablen-isleft)/2));
if (node->left != NULL)
{
for (i=1; i <= node->edge_length && y+i < MAX_HEIGHT; i++)
{
lprofile[y+i] = MIN(lprofile[y+i], x-i);
}
}
compute_lprofile(node->left, x-node->edge_length-1, y+node->edge_length+1);
compute_lprofile(node->right, x+node->edge_length+1, y+node->edge_length+1);
}
void compute_rprofile(asciinode *node, int x, int y)
{
int i, notleft;
if (node == NULL) return;
notleft = (node->parent_dir != -1);
rprofile[y] = MAX(rprofile[y], x+((node->lablen-notleft)/2));
if (node->right != NULL)
{
for (i=1; i <= node->edge_length && y+i < MAX_HEIGHT; i++)
{
rprofile[y+i] = MAX(rprofile[y+i], x+i);
}
}
compute_rprofile(node->left, x-node->edge_length-1, y+node->edge_length+1);
compute_rprofile(node->right, x+node->edge_length+1, y+node->edge_length+1);
}
//This function fills in the edge_length and
//height fields of the specified tree
void compute_edge_lengths(asciinode *node)
{
int h, hmin, i, delta;
if (node == NULL) return;
compute_edge_lengths(node->left);
compute_edge_lengths(node->right);
/* first fill in the edge_length of node */
if (node->right == NULL && node->left == NULL)
{
node->edge_length = 0;
}
else
{
if (node->left != NULL)
{
for (i=0; i<node->left->height && i < MAX_HEIGHT; i++)
{
rprofile[i] = -INFINITY;
}
compute_rprofile(node->left, 0, 0);
hmin = node->left->height;
}
else
{
hmin = 0;
}
if (node->right != NULL)
{
for (i=0; i<node->right->height && i < MAX_HEIGHT; i++)
{
lprofile[i] = INFINITY;
}
compute_lprofile(node->right, 0, 0);
hmin = MIN(node->right->height, hmin);
}
else
{
hmin = 0;
}
delta = 4;
for (i=0; i<hmin; i++)
{
delta = MAX(delta, gap + 1 + rprofile[i] - lprofile[i]);
}
//If the node has two children of height 1, then we allow the
//two leaves to be within 1, instead of 2
if (((node->left != NULL && node->left->height == 1) ||
(node->right != NULL && node->right->height == 1))&&delta>4)
{
delta--;
}
node->edge_length = ((delta+1)/2) - 1;
}
//now fill in the height of node
h = 1;
if (node->left != NULL)
{
h = MAX(node->left->height + node->edge_length + 1, h);
}
if (node->right != NULL)
{
h = MAX(node->right->height + node->edge_length + 1, h);
}
node->height = h;
}
//This function prints the given level of the given tree, assuming
//that the node has the given x cordinate.
void print_level(asciinode *node, int x, int level)
{
int i, isleft;
if (node == NULL) return;
isleft = (node->parent_dir == -1);
if (level == 0)
{
for (i=0; i<(x-print_next-((node->lablen-isleft)/2)); i++)
{
printf(" ");
}
print_next += i;
printf("%s", node->label);
print_next += node->lablen;
}
else if (node->edge_length >= level)
{
if (node->left != NULL)
{
for (i=0; i<(x-print_next-(level)); i++)
{
printf(" ");
}
print_next += i;
printf("/");
print_next++;
}
if (node->right != NULL)
{
for (i=0; i<(x-print_next+(level)); i++)
{
printf(" ");
}
print_next += i;
printf("\\");
print_next++;
}
}
else
{
print_level(node->left,
x-node->edge_length-1,
level-node->edge_length-1);
print_level(node->right,
x+node->edge_length+1,
level-node->edge_length-1);
}
}
//prints ascii tree for given Tree structure
void print_ascii_tree(Tree * t)
{
asciinode *proot;
int xmin, i;
if (t == NULL) return;
proot = build_ascii_tree(t);
compute_edge_lengths(proot);
for (i=0; i<proot->height && i < MAX_HEIGHT; i++)
{
lprofile[i] = INFINITY;
}
compute_lprofile(proot, 0, 0);
xmin = 0;
for (i = 0; i < proot->height && i < MAX_HEIGHT; i++)
{
xmin = MIN(xmin, lprofile[i]);
}
for (i = 0; i < proot->height; i++)
{
print_next = 0;
print_level(proot, -xmin, i);
printf("\n");
}
if (proot->height >= MAX_HEIGHT)
{
printf("(This tree is taller than %d, and may be drawn incorrectly.)\n", MAX_HEIGHT);
}
free_ascii_tree(proot);
}
void print(BST B)
{
print_ascii_tree(B);
}
int isEmptyBST(BST B)
{
return(B == NULL);
}
/*
int supprimer(ABR *pA, int Elt)
{
if (arbre_vide(*pA))
return 0;
if ((*pA)->racine == Elt)
enlever_racine(pA);
else
if ((*pA)->racine > Elt)
supprimer(&((*pA)->SAG),Elt);
else
supprimer(&((*pA)->SAD),Elt);
return 1;
}
*/
void delete_root(BST *B)
{
BST C, D;
if( (*B)->left == (*B)->right && (*B)->right==NULL)
{
C=*B;
free(C);
*B=NULL;
}
else
if((*B)->right==NULL)
{
C=(*B);
*B=(*B)->left;
free(C);
}
else
if((*B)->left==NULL)
{
C=(*B);
*B=(*B)->right;
free(C);
}
else // find the max on the right
{
C=(*B)->right;
if(C->left==NULL)
{
(*B)->right=C->right;
(*B)->element=C->element;
free(C);
}
else
{
while(C->left!=NULL)
{
D=C;
C=C->left;
}
(*B)->element=C->element;
D->left=C->right;
free(C);
}
}
}
int belong(BST A, int Elt)
{
if (isEmptyBST(A)) return 0;
else if (A->element == Elt) return 1;
else if (A->element > Elt) return belong(A->left,Elt);
return belong(A->right,Elt);
}
void eliminate_in_commun(BST A, BST *B)
{
if (*B)
{
// print(*B);
if (belong(A,(*B)->element))
{
delete_root(B);
eliminate_in_commun(A,B);
}
else
{
eliminate_in_commun(A,&((*B)->left));
eliminate_in_commun(A,&((*B)->right));
}
}
}
void insert_BST(BST *B, int Elt)
{
if (isEmptyBST(*B))
{
*B = (BST) malloc(sizeof(Tree));
(*B)->element=Elt;
(*B)->left=(*B)->right=NULL;
}
else
if ((*B)->element >= Elt)
insert_BST(&((*B)->left),Elt);
else
insert_BST(&((*B)->right),Elt);
}
void inorder(BST B)
{
if(B)
{
inorder(B->left);
printf("%d ",B->element);
inorder(B->right);
}
}
void preorder(BST B)
{
if(B)
{
printf("%d ",B->element);
preorder(B->left);
preorder(B->right);
}
}
void postorder(BST B)
{
if(B)
{
postorder(B->left);
postorder(B->right);
printf("%d ",B->element);
}
}
int main()
{
BST A, B;
int n1, n2, i, nb;
int tests;
scanf("%d",&tests);
while(tests--)
{
A=NULL;
B=NULL;
scanf("%d",&n1);
for(i=0; i<n1; i++)
{
scanf("%d",&nb);
insert_BST(&A,nb);
}
scanf("%d",&n2);
for(i=0; i<n2; i++)
{
scanf("%d",&nb);
insert_BST(&B,nb);
}
eliminate_in_commun(A,&B);
inorder(B); printf("\n");
preorder(B); printf("\n");
postorder(B); printf("\n");
printf("\n");
}
return 0;
}
Back to the list of exercises
Looking for a more challenging exercise, try this one !!
Merge two arrays into a third sorted array