Skillversitas

Binary Search

Binary Search is a very efficient search algorithm for sorted data. It works by halving the search area at every step.

Requirement

The array must be sorted before using binary search.

Iterative Implementation

def binary_search(arr, target):
    low, high = 0, len(arr) - 1

    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return -1

Recursive Implementation

def binary_search_recursive(arr, target, low, high):
    if low > high:
        return -1

    mid = (low + high) // 2
    if arr[mid] == target:
        return mid
    elif arr[mid] < target:
        return binary_search_recursive(arr, target, mid + 1, high)
    else:
        return binary_search_recursive(arr, target, low, mid - 1)

Example

data = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
print(binary_search(data, 23))   # 5
print(binary_search(data, 100))  # -1

Visualization

Find 23 in [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]

Step 1: low=0, high=9, mid=4 -> arr[4]=16 < 23
Step 2: low=5, high=9, mid=7 -> arr[7]=56 > 23
Step 3: low=5, high=6, mid=5 -> arr[5]=23 = 23 ✓

Variation: Lower Bound

Finds the index of the first occurrence of the element.

def lower_bound(arr, target):
    low, high = 0, len(arr) - 1
    result = -1

    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            result = mid
            high = mid - 1  # Look for something smaller
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return result

Variation: Upper Bound

Finds the index of the last occurrence of the element + 1.

def upper_bound(arr, target):
    low, high = 0, len(arr) - 1
    result = -1

    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            result = mid
            low = mid + 1  # Look for something larger
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return result

Edge Cases

# Empty array
binary_search([], 5)  # -1

# Single element
binary_search([5], 5)  # 0
binary_search([3], 5)  # -1

# Target at the start/end
binary_search([1, 2, 3, 4, 5], 1)  # 0
binary_search([1, 2, 3, 4, 5], 5)  # 4

Time Complexity

Case Time
Best O(1)
Average O(log n)
Worst O(log n)

Space Complexity

  • Iterative: O(1)
  • Recursive: O(log n) due to the call stack

Binary Search is very efficient. Now let's study Dijkstra for shortest paths.