Free for students · Ad-free · WCAG 2.1 AA Compliant · Accessibility

Recursive Searching and Sorting

Lesson ~11 min read 8 MCQs

In simple terms: In simple terms, recursive searching and sorting is about using a "divide and conquer" strategy to find items in a list or to put a list in order, like a super-efficient librarian.

Why this matters

Imagine you're in the school library, looking for a single definition in a massive, 1,500-page dictionary. You could start at page one and flip through every single page until you find your word. That's called a linear search, and it works, but it's slow and painful. What if you're looking for the word "recursive"? You know it's in the 'R' section, somewhere in the back half of the book.

So, you open the dictionary right to the middle. You land in the 'M's. You know 'R' comes after 'M', so you can completely ignore the entire first half of the book. You just eliminated 750 pages in one move. Now you take the back half and open it to the middle... and so on.

This "divide and conquer" approach is the heart of what we're learning today. We'll explore two powerful, recursive algorithms that use this same logic: Binary Search, for finding things in a sorted list, and Merge Sort, for sorting a jumbled list in the first place.

Concept overview

flowchart TD
    A[Start: Sorted Array, Target] --> B{low > high?};
    B -- Yes --> C[Not Found. Return -1];
    B -- No --> D[mid = (low + high) / 2];
    D --> E{arr[mid] == Target?};
    E -- Yes --> F[Found! Return mid];
    E -- No --> G{Target < arr[mid]?};
    G -- Yes --> H[Search Left Half: high = mid - 1];
    G -- No --> I[Search Right Half: low = mid + 1];
    H --> B;
    I --> B;
This diagram shows a flowchart of the binary search algorithm. It starts with a sorted array and a target value, then enters a loop that checks if the search range is still valid. If it is, it finds the middle element and compares it to the target, deciding whether to search the left half, the right half, or if the element has been found.

Core explanation

Hey everyone, it's Saavi. Let's dive into two of the most elegant ideas in computer science. They might feel a little abstract at first, but once you see the pattern, you'll appreciate how clever and powerful they are.

Recursion on Collections

Before we get to the big algorithms, let's quickly refresh how recursion works on data collections like String objects or arrays. Remember, a recursive solution has two parts:

  1. 1
    Base Case
    The simplest possible problem that can be solved directly, which stops the recursion.
  2. 2
    Recursive Step
    The part that breaks the problem into a smaller version of itself and calls the method again on that smaller piece.

For example, you could write a recursive method to check if a word is a palindrome. The base case might be a word with 0 or 1 letters (which is always a palindrome). The recursive step would check if the first and last letters match, and if they do, you'd recursively call the method on the substring without those letters. This idea of breaking a collection down is fundamental to what follows.

Binary Search: The Smartest Guessing Game

Binary search is your go-to algorithm for finding an element in a sorted collection. I can't stress that enough.

The Golden Rule: Binary search only works on sorted data. If you try to run it on an unsorted array of numbers from a basketball game's stats, you'll get incorrect results or miss the value entirely. Why? Because the whole algorithm relies on being able to eliminate half the data based on a comparison, just like with the dictionary example.

Here's how it works on a sorted array:

  1. 1
    Find the middle
    You look at the element right in the middle of the array.
  2. 2
    Compare
    • Is this the element you're looking for? If yes, you're done! That's a base case.
    • Is your target value smaller than the middle element? If yes, you know it must be in the left half. You can completely ignore the right half.
    • Is your target value larger than the middle element? If yes, you know it must be in the right half. You can ignore the left half.
  3. 3
    Recurse
    You repeat the process on the remaining half of the array.

This process continues until you either find the element or the search space runs out (meaning the element isn't in the array). Each step cuts your search space in half, which makes it incredibly fast—much more efficient than checking every single element one by one (linear search).

While you can write binary search with a while loop (iteratively), the recursive version is a beautiful demonstration of a "divide and conquer" strategy.

// A conceptual look at recursive binary search
public int binarySearch(int[] arr, int target, int low, int high) {
    if (low > high) {
        return -1; // Base case: not found
    }

    int mid = low + (high - low) / 2; // Avoids potential overflow

    if (arr[mid] == target) {
        return mid; // Base case: found!
    } else if (target < arr[mid]) {
        // Recursive step: search the left half
        return binarySearch(arr, target, low, mid - 1);
    } else {
        // Recursive step: search the right half
        return binarySearch(arr, target, mid + 1, high);
    }
}

Merge Sort: Divide, Conquer, and Combine

What if your data isn't sorted? You need an efficient way to sort it. Enter Merge Sort.

Merge sort is a recursive sorting algorithm that is famous for its reliability and efficiency. It follows the "divide and conquer" mantra perfectly.

That's the Divide step. Merge sort recursively splits the array in half until it's broken down into a series of one-element arrays.

[8, 3, 5, 1] -> [8, 3] and [5, 1] -> [8], [3], [5], [1]

Now comes the Conquer (or Merge) step. This is the real work. Starting with those single-element arrays, you merge them back together in sorted order.

  1. You take two adjacent "piles" (which are already sorted) and a new, empty "pile".
  2. You look at the top form of each pile. Whichever comes first alphabetically, you move it to your new, merged pile.
  3. You repeat this, always comparing the top forms of your two source piles, until one pile is empty.
  4. Then, you just add the rest of the remaining pile to the end of your new pile.

You repeat this merging process up the chain. The two-form piles get merged into sorted four-form piles, which get merged into sorted eight-form piles, and so on, until you have one, big, perfectly sorted stack of forms.

Merge sort is a workhorse. It's more predictable than other sorting algorithms you might see later, and its efficiency is a benchmark for sorting.

See it in action

Java Code

      
      
Call Stack
Stack is empty — waiting for first call.
Step 0 / 0

Worked examples

Let's trace these algorithms so you can see them in action. Tracing is a critical skill for the AP exam.

Example 1

Binary Search Trace

Problem: Your friend Priya gives you a sorted list of her top scores from an arcade game: [120, 155, 210, 280, 350, 490, 510, 600]. Use binary search to find out if she ever scored 210.

We'll keep track of the low index, the high index, and the mid index. Initially, low = 0 and high = 7.

Iteration 1:

  • Array portion
    [120, 155, 210, 280, 350, 490, 510, 600]
  • low = 0, high = 7
  • Calculate middle
    mid = (0 + 7) / 2 = 3 (integer division).
  • Compare
    The element at index 3 is 280.
  • Decision
    Our target 210 is less than 280. So, we know our answer (if it exists) must be in the left half. We discard the middle element and everything to its right.
  • Next step
    Our new search space is from index 0 to mid - 1, which is 2. So, low stays 0, high becomes 2.

Iteration 2:

  • Array portion
    [120, 155, 210]
  • low = 0, high = 2
  • Calculate middle
    mid = (0 + 2) / 2 = 1.
  • Compare
    The element at index 1 is 155.
  • Decision
    Our target 210 is greater than 155. We discard the middle element and everything to its left.
  • Next step
    Our new search space is from mid + 1 to high. So, low becomes 2, high stays 2.

Iteration 3:

  • Array portion
    [210]
  • low = 2, high = 2
  • Calculate middle
    mid = (2 + 2) / 2 = 2.
  • Compare
    The element at index 2 is 210.
  • Decision
    This is our target! We found it at index 2. The algorithm returns 2.
Example 2

Merge Sort Trace

Problem: Sort the following array of customer wait times (in minutes) at a popular Boston food truck: [9, 4, 7, 2].

Step 1: The "Divide" Phase The algorithm recursively splits the array until each element is in its own subarray.

  1. [9, 4, 7, 2] is split into [9, 4] and [7, 2].
  2. [9, 4] is split into [9] and [4].
  3. [7, 2] is split into [7] and [2].

Now we have our base cases: four arrays of size one. [9], [4], [7], [2].

Step 2: The "Merge" Phase Now we merge them back together in sorted order.

  1. Merge [9] and [4]:

    • Compare 9 and 4. 4 is smaller.
    • The merged result is [4, 9].
  2. Merge [7] and [2]:

    • Compare 7 and 2. 2 is smaller.
    • The merged result is [2, 7].
  3. Merge [4, 9] and [2, 7]:

    • This is the most important step. We have two sorted lists and we'll create a new one.
    • Compare the first elements: 4 and 2. 2 is smaller. Our new list is [2].
    • The lists are now [4, 9] and [7].
    • Compare the first elements: 4 and 7. 4 is smaller. Our new list is [2, 4].
    • The lists are now [9] and [7].
    • Compare the first elements: 9 and 7. 7 is smaller. Our new list is [2, 4, 7].
    • The lists are now [9] and []. The second list is empty.
    • We just add the remaining elements from the first list (9).
    • The final merged result is [2, 4, 7, 9].

The array is now sorted!

Try it yourself

Ready to try it yourself? Grab a piece of paper and trace the logic.

Problem 1: Binary Search Practice You have a sorted ArrayList of product IDs from a warehouse in Dallas: [101, 115, 132, 247, 301, 302, 450, 489, 512].

Trace the steps of a recursive binary search to find the product with ID 450. Keep track of the low, high, and mid indices for each recursive call. What are they for the second recursive call?

Problem 2: Merge Sort Practice You're given an array of unsorted scores from a school's soccer tryouts: [88, 75, 92, 81, 79, 95].

Show the result of the first merge operation that would happen after the array is completely split. Then, show the result of merging [75, 88] and [81, 92] together.