|
1 |
| -#!/usr/bin/env python3 |
2 |
| - |
3 | 1 | """
|
4 |
| -Pure Python implementation of exponential search algorithm |
| 2 | +Exponential Search Algorithm |
5 | 3 |
|
6 |
| -For more information, see the Wikipedia page: |
7 |
| -https://en.wikipedia.org/wiki/Exponential_search |
| 4 | +Time Complexity: |
| 5 | +- Best Case: O(1) |
| 6 | +- Average/Worst Case: O(log i), where i is the index of the first element >= target |
8 | 7 |
|
9 |
| -For doctests run the following command: |
10 |
| -python3 -m doctest -v exponential_search.py |
| 8 | +Use Case: |
| 9 | +Efficient for searching in sorted arrays where the target is near the beginning. |
11 | 10 |
|
12 |
| -For manual testing run: |
13 |
| -python3 exponential_search.py |
| 11 | +Author: Michael Alexander Montoya |
14 | 12 | """
|
15 | 13 |
|
16 |
| -from __future__ import annotations |
17 |
| - |
18 |
| - |
19 |
| -def binary_search_by_recursion( |
20 |
| - sorted_collection: list[int], item: int, left: int = 0, right: int = -1 |
21 |
| -) -> int: |
22 |
| - """Pure implementation of binary search algorithm in Python using recursion |
23 |
| -
|
24 |
| - Be careful: the collection must be ascending sorted otherwise, the result will be |
25 |
| - unpredictable. |
26 |
| -
|
27 |
| - :param sorted_collection: some ascending sorted collection with comparable items |
28 |
| - :param item: item value to search |
29 |
| - :param left: starting index for the search |
30 |
| - :param right: ending index for the search |
31 |
| - :return: index of the found item or -1 if the item is not found |
32 |
| -
|
33 |
| - Examples: |
34 |
| - >>> binary_search_by_recursion([0, 5, 7, 10, 15], 0, 0, 4) |
35 |
| - 0 |
36 |
| - >>> binary_search_by_recursion([0, 5, 7, 10, 15], 15, 0, 4) |
37 |
| - 4 |
38 |
| - >>> binary_search_by_recursion([0, 5, 7, 10, 15], 5, 0, 4) |
39 |
| - 1 |
40 |
| - >>> binary_search_by_recursion([0, 5, 7, 10, 15], 6, 0, 4) |
41 |
| - -1 |
42 |
| - """ |
43 |
| - if right < 0: |
44 |
| - right = len(sorted_collection) - 1 |
45 |
| - if list(sorted_collection) != sorted(sorted_collection): |
46 |
| - raise ValueError("sorted_collection must be sorted in ascending order") |
47 |
| - if right < left: |
| 14 | +def exponential_search(arr, target): |
| 15 | + if len(arr) == 0: |
48 | 16 | return -1
|
49 | 17 |
|
50 |
| - midpoint = left + (right - left) // 2 |
51 |
| - |
52 |
| - if sorted_collection[midpoint] == item: |
53 |
| - return midpoint |
54 |
| - elif sorted_collection[midpoint] > item: |
55 |
| - return binary_search_by_recursion(sorted_collection, item, left, midpoint - 1) |
56 |
| - else: |
57 |
| - return binary_search_by_recursion(sorted_collection, item, midpoint + 1, right) |
58 |
| - |
59 |
| - |
60 |
| -def exponential_search(sorted_collection: list[int], item: int) -> int: |
61 |
| - """ |
62 |
| - Pure implementation of an exponential search algorithm in Python. |
63 |
| - For more information, refer to: |
64 |
| - https://en.wikipedia.org/wiki/Exponential_search |
65 |
| -
|
66 |
| - Be careful: the collection must be ascending sorted, otherwise the result will be |
67 |
| - unpredictable. |
68 |
| -
|
69 |
| - :param sorted_collection: some ascending sorted collection with comparable items |
70 |
| - :param item: item value to search |
71 |
| - :return: index of the found item or -1 if the item is not found |
72 |
| -
|
73 |
| - The time complexity of this algorithm is O(log i) where i is the index of the item. |
74 |
| -
|
75 |
| - Examples: |
76 |
| - >>> exponential_search([0, 5, 7, 10, 15], 0) |
77 |
| - 0 |
78 |
| - >>> exponential_search([0, 5, 7, 10, 15], 15) |
79 |
| - 4 |
80 |
| - >>> exponential_search([0, 5, 7, 10, 15], 5) |
81 |
| - 1 |
82 |
| - >>> exponential_search([0, 5, 7, 10, 15], 6) |
83 |
| - -1 |
84 |
| - """ |
85 |
| - if list(sorted_collection) != sorted(sorted_collection): |
86 |
| - raise ValueError("sorted_collection must be sorted in ascending order") |
87 |
| - |
88 |
| - if sorted_collection[0] == item: |
| 18 | + if arr[0] == target: |
89 | 19 | return 0
|
90 | 20 |
|
91 |
| - bound = 1 |
92 |
| - while bound < len(sorted_collection) and sorted_collection[bound] < item: |
93 |
| - bound *= 2 |
| 21 | + # Find range for binary search by repeated doubling |
| 22 | + index = 1 |
| 23 | + while index < len(arr) and arr[index] <= target: |
| 24 | + index *= 2 |
94 | 25 |
|
95 |
| - left = bound // 2 |
96 |
| - right = min(bound, len(sorted_collection) - 1) |
97 |
| - return binary_search_by_recursion(sorted_collection, item, left, right) |
| 26 | + # Perform binary search in the found range |
| 27 | + return binary_search(arr, target, index // 2, min(index, len(arr)-1)) |
98 | 28 |
|
99 | 29 |
|
100 |
| -if __name__ == "__main__": |
101 |
| - import doctest |
| 30 | +def binary_search(arr, target, left, right): |
| 31 | + while left <= right: |
| 32 | + mid = (left + right) // 2 |
| 33 | + if arr[mid] == target: |
| 34 | + return mid |
| 35 | + elif arr[mid] < target: |
| 36 | + left = mid + 1 |
| 37 | + else: |
| 38 | + right = mid - 1 |
| 39 | + return -1 |
102 | 40 |
|
103 |
| - doctest.testmod() |
104 | 41 |
|
105 |
| - # Manual testing |
106 |
| - user_input = input("Enter numbers separated by commas: ").strip() |
107 |
| - collection = sorted(int(item) for item in user_input.split(",")) |
108 |
| - target = int(input("Enter a number to search for: ")) |
109 |
| - result = exponential_search(sorted_collection=collection, item=target) |
110 |
| - if result == -1: |
111 |
| - print(f"{target} was not found in {collection}.") |
112 |
| - else: |
113 |
| - print(f"{target} was found at index {result} in {collection}.") |
| 42 | +# Example usage: |
| 43 | +if __name__ == "__main__": |
| 44 | + array = [1, 3, 5, 7, 9, 13, 17, 21, 24, 27, 30] |
| 45 | + target = 13 |
| 46 | + result = exponential_search(array, target) |
| 47 | + print(f"Target {target} found at index: {result}") |
0 commit comments