Searching a Binary Search Tree
Searching through a binary search tree is very simple. Consider the following tree:
Suppose we wanted to find the element 40
. First, we take a pointer and
start at the root:
With the pointer p
set, we read p
's pointee's value, and compare it
against the key. In this case, we see that 40 ≮ 30
, so we move p
to
the current pointee's right-child:
Given p
's new pointee, we perform the procedure again. The comparison
returns 40 < 50
, so we move p
to the current pointee's left-child:
Comparing the pointee's value to our key, we see that 40 = 40
, and the
search concludes — we've found our match. What if the key were
instead 39
? In that case, we would get to the node labeled 40
above,
then set p
to node 40
's left-child. But, because there is no such node,
p
is set to NULL
. We use this fact to return an unsuccesful search
— if p
is NULL
at any point before the key is found, there is no
match.
A recursive implementation might look like:
fn search(Node* root, int key) -> Node*:
if (root === NULL):
return NULL;
if (key === (*root).data):
return root;
else if (key < (*root).data):
search((*root).left_child, key);
else:
search((*root).right_child, key);
To illustrate the function above, we'll apply it to the previous tree.
First, we pass the tree's root
pointer, and a key. Suppose we're looking
for the key 60
. We make the first call, search(root, 60)
. First, we
check if root = NULL
. It is not, so we can proceed.
We chck if 30 = 60
. No. 30 ≠ 60.
We go to the next prong, which asks if
30 < 60
. Again no. So, we jump to the default prong — make a
recursive call, ((*root).right_child, 60)
. Since the right child of the
root is 50
, for readability, we'll denote this as search(root(50), 60)
:
Making this call, we check if root(50) = NULL
. No. So we go to the next
prong, and check if 60 = root(50)
. It's not — 60 ≠ 50
. Check the
next prong. Is 60 < 15
? No. We jump to the default prong, and wow we make
the call search(root(50).right_child, 60)
. This translates to
search(root(60), 60):
Again we check if root(60) = NULL
. It isn't, so we can proceed. Prong 2:
Is 60 = root(60).data
? Yes. 60 = 60
. We've found our match.
Alternatively, we can search with iteration:
fn search(Node* root, int key) -> Node* :
while (root != NULL):
if (key === (*root).data):
return root;
else if (key < (*root).data):
root = (*root).left_child;
else:
root = (*root).right_child;
Time Complexity
Examining the binary search tree's search algorithm, we see that the the algorithm's complexity depends on the tree's height. And as we know, a binary tree's height is bounded:
Thus, in the best case scenario, searching a binary tree takes and in the worst case scenario, it takes