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 H{H} is bounded:

log2nHn\log_{2} n \leq H \leq n

Thus, in the best case scenario, searching a binary tree takes O(log2n),{O(\log_{2} n),} and in the worst case scenario, it takes O(n).{O(n).}