# 5 Best Ways to Explain Binary Search in Python

Rate this post

π‘ Problem Formulation: Understanding binary search in Python requires grasping how the algorithm efficiently locates an item in a sorted sequence by repeatedly dividing the search space in half. For instance, given a list of sorted numbers, `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`, and a target value `7`, the binary search method should return the index that corresponds to the location of the target value in the list, which would be `6` in our example.

## Method 1: Iterative Binary Search

Iterative binary search is the conventional technique whereby the algorithm iteratively narrows down the search interval with the help of two pointers that indicate the start and end of the range that might contain the target. The function specification is simple: provide a sorted array and the target, the function then returns the index of the target or -1 if not found.

Here’s an example:

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

while low <= high:
mid = (low + high) // 2
guess = arr[mid]

if guess == target:
return mid
if guess > target:
high = mid - 1
else:
low = mid + 1

return -1

# Example usage
index_found = iterative_binary_search([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 7)
print(index_found)
```

The output of this code snippet would be: `6`

This code defines a function `iterative_binary_search` that receives a sorted list and a target value. By adjusting the `low` and `high` pointers within the loop, the function continuously narrows down the search. Upon finding the target, it returns the index, or -1 if the target is not in the list.

## Method 2: Recursive Binary Search

Recursive binary search leverages the call stack to divide the problem into smaller subproblems, which can be more intuitive for some practitioners. A function using this approach takes the array, target, and the start and end indices of the search interval as arguments, returning the index of the target or -1 if not found.

Here’s an example:

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

# Example usage
index_found = recursive_binary_search([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 7, 0, 9)
print(index_found)
```

The output of this code snippet would be: `6`

The `recursive_binary_search` function operates on the principle of recursion. If the subarray has only one item or no items (base case), it concludes the search. Otherwise, it calls itself with updated bounds.

## Method 3: Binary Search Using Python’s `bisect` Module

Python provides the `bisect` module with functions such as `bisect_left` which can be used to implement binary search directly. The function takes in a sorted array and the target, and returns the insertion point which serves as the index if the element exists.

Here’s an example:

```import bisect

def bisect_binary_search(arr, target):
index = bisect.bisect_left(arr, target)
if index != len(arr) and arr[index] == target:
return index
return -1

# Example usage
index_found = bisect_binary_search([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 7)
print(index_found)
```

The output of this code snippet would be: `6`

In this code, `bisect_binary_search` is a wrapper around `bisect.bisect_left`, which finds the point of insertion for the target to maintain order. If the target is present at the insertion index, that index is returned.

## Method 4: Binary Search using Standard Library

The standard library in Python 3 has a function `array.bisect()` which is a shorthand for the `bisect` module’s functions. It easens the process of applying binary search by abstracting out the lower level operations.

Here’s an example:

```from array import array
from bisect import bisect_left

def library_binary_search(arr, target):
index = bisect_left(arr, target)
if index != len(arr) and arr[index] == target:
return index
return -1

# Example usage
index_found = library_binary_search(array('i', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 7)
print(index_found)
```

The output of this code snippet would be: `6`

This function `library_binary_search` utilizes the `bisect_left` function from the `bisect` module and the type-specific array from the `array` module. This is an example of leveraging the library for binary search without manual loop construction.

## Bonus One-Liner Method 5: List Comprehension Approach

While list comprehension is not typically associated with binary search, it can be used in a somewhat forced, but concise manner to replicate the finding process by generating indices and filtering based on conditions.

Here’s an example:

```arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
target = 7

index_found = next((i for i, x in enumerate(arr) if x == target), -1)
print(index_found)
```

The output of this code snippet would be: `6`

The one-liner defines a generator inside the `next()` function that enumerates the list and yields the index if the current value equals the target. If the target is not found, it defaults to `-1`.

## Summary/Discussion

• Method 1: Iterative Binary Search. Strengths: straightforward, control over iteration, and widely accepted. Weaknesses: requires explicit handling of loop conditions.
• Method 2: Recursive Binary Search. Strengths: elegant and brief recursive code. Weaknesses: may lead to maximum recursion depth exceeded in large datasets.
• Method 3: Binary Search with `bisect` module. Strengths: compact, uses built-in features, efficient implementation. Weaknesses: may be slower than manual implementations for long lists.
• Method 4: Binary Search using Standard Library. Strengths: utilizes efficient and optimized library code. Weaknesses: not as instructive for learning how the underlying algorithm works.
• Method 5: List Comprehension Approach. Strengths: one-liner, quick to write. Weaknesses: not a true binary search, lacks efficiency of other methods, can be unclear to readers.