Learning Tree Data Structure
Binary Search Tree: Coding Mode On
Now it’s coding time! What will we see here? Insertion, search for a value, deletion, and balance the tree
. Let’s the game begin
Insertion: adding new nodes to our tree
Imagine we have an empty tree
and we want to start adding new nodes
with these values: 50, 76, 21, 4, 32, 100, 64, 52. In that order.
The first thing we need to know is 50 is the root
of our tree
.
So now we can start inserting node
by node
.
- 76: greater than 50, insert on the right side.
- 21: smaller than 50, insert on the left side.
- 4: smaller than 50.
Node
with value 50 has aleft child
(21). 4 is smaller than 21, insert it on the left side of thisnode
- 32: smaller than 50.
Node
with value 50 has aleft child
(21). 32 is greater than 21, insert it on the right side of thisnode
. - 100: greater than 50.
Node
with value 50 has aright child
(76). 100 is greater than 76, insert it on the right side of thisnode
. - 64: greater than 50.
Node
with value 50 has aright child
node
. - 52: greater than 50.
Node
with value 50 has aright child
(76). 52 is smaller than 76.Node
with value 76 has aleft child
(64). 52 is smaller than 64, insert it on the left side of thisnode
.
Did you notice a pattern here? Let’s break it down.
- Ask “Is the new
node
value greater or smaller than the currentnode
?” - Is the new
node
value greater than the currentnode
? Go to the rightsubtree
. If the currentnode
doesn’t have aright child
, insert it there. Else backtrack to rule number 1. - Is the new
node
value smaller than the currentnode
? Go to the leftsubtree
. If the currentnode
doesn’t have aleft child
, insert it there. Else backtrack to rule number 1. - Special case we didn’t handle: when new
node
value is equal to the currentnode
‘s value. Just use the rule number 3. Consider equal values to insert in the leftsubtree
part.
Now the code! yey!
It seems very simple. The powerful part of this algorithm is the recursion part: line 9
and line 13
. Both lines of code call the insert_node
method, for its left
and right
children
, respectively. Lines 11
and 15
are the ones that we do the insertion for each child
.
Searching: let’s find the node value. Or not
The algorithm that we will build now is all about searching. For a given value (integer number), we will say if our Binary Search Tree
has or hasn’t that value.
One important part is how we defined the tree
insertion algorithm. First we have our root
node
. All the left subtree
nodes
will have smaller values than the root
node
. And all the right subtree
nodes
will have greater values than the root
node
.
Example time! Imagine we have this tree
.
Now we want to know if we find a node based on a given value 52.
Let’s break it down.
- We start with the
root
node
as our currentnode
. Is the given value smaller than the currentnode
value? If yes, then we will search it on the leftsubtree
. - Is the given value greater than the current
node
value? If yes, then we will search it on the rightsubtree
. - If rules number 1 and number 2 are both false, we can compare the current
node
value and the given value if they are equal. If the return of the comparison istrue
then “Yeah! Ourtree
has the given value”. Else “Nooo. It hasn’t”.
Coding time!
- Lines 8 and 9 are the rule number 1.
- Lines 10 and 11 are the rule number 2.
- Line 13 is the rule number 3.
How do we test it?
Let’s create our Binary Search Tree
initializing the root
node
with the value 15.
And now we will insert a lot of new nodes
there.
For each inserted node
we will test if our find_node
method really works.
Yeah, it works for these given values! Let’s test for a value that doesn’t exist in our Binary Search Tree
.
Oh yeah! Searching… done!
Deletion: removing and organizing
Deletion is a more complex algorithm, because we need to handle different cases. For a given value, we need to remove the node
with this value. Imagine that this node
has not children
, or a single child
, or two children
.
- Case 1: A
node
with nochildren
(leaf
node
).
If the node
we want to delete has no children, we simply delete it. The algorithm doesn’t need to reorganize the tree
.
- Case 2: A
node
with just one child (left
orright
child).
To cover the second case, our algorithm needs to make the node
’s parent points to the node
‘s child
. If the node
is the left child
of its parent, we make the node
’s parent left child
points to the node
‘s child
. If the node
is the right child
of its parent, we make the node
’s parent right child
points to the node
‘s child
.
- Case 3: A
node
with two children.
When the node
has 2 children, we need to find the node
with the minimum value starting from the node
‘s right child
. We will put this node
with minimum value in the place of the node
we want to remove.
Coding time!
- First thing: the parameters.
value
andparent
. We want to find thenode
that has thisvalue
and thenode
’s parent is a important part to remove thenode
. - Second thing: the returning value. Our algorithm will return a boolean value.
True
if it found thenode
and removed it. OtherwiseFalse
. - From line 2 to line 9: we start searching for the
node
that has thevalue
we are looking for. If thevalue
is smaller than thecurrent node
value
we go to theleft subtree
, recursively (if and only if thecurrent node
has aleft child
). If thevalue
is greater, go to theright subtree
, recursively. - Line 10: we start to think about the
remove
algorithm. - From line 11 to line 13: we cover the
node
with nochildren
and it is theleft child
from itsparent
. We remove thenode
by setting theparent
’sleft child
toNone
. - Lines 14 and 15: we cover the
node
with just nochildren
and it is theright child
from itsparent
. We remove thenode
by setting theparent
’sright child
toNone
. - Clear node method: I will show the
clear_node
code below. But basically it set thenode
left child
,right child
, and itsvalue
toNone
. - From line 16 to line 18: we cover the
node
with just onechild
(left child
) and it is theleft child
from itsparent
. We set theparent
'sleft child
to thenode
’sleft child
(the only child it has). - From line 19 to line 21: we cover the
node
with just onechild
(left child
) and it is theright child
from itsparent
. We set theparent
'sright child
to thenode
’sleft child
(the only child it has). - From line 22 to line 24: we cover the
node
with just onechild
(right child
) and it is theleft child
from itsparent
. We set theparent
'sleft child
to thenode
’sright child
(the only child it has). - From line 25 to line 27: we cover the
node
with just onechild
(right child
) and it is theright child
from itsparent
. We set theparent
'sright child
to thenode
’sright child
(the only child it has). - From line 28 to line 30: we cover the
node
with bothleft
andright
children. We get thenode
with the smallestvalue
(code below!) and set it to thecurrent node
‘svalue
. Finish it by removing the smallestnode
. - Line 32: if we found the
node
we are looking for, we need to returnTrue
. From line 11 to line 31 we handle this case. So just returnTrue
and that’s it!