ADA-Python / algorithms /search.py
ussu321's picture
Upload 50 files
bd86de0 verified
Raw
History Blame Contribute Delete
9.55 kB
"""
USSU Algorithm Analyzer v4.0 - Searching Algorithms Suite
Complete with complexity tracking, metrics, and step logging.
"""
import math
import time
import random
from typing import List, Dict, Any, Optional
from utils.core import profile_algorithm, OperationCounter
class SearchingAlgorithms(OperationCounter):
"""Complete suite of searching algorithms"""
def __init__(self):
super().__init__()
self.steps: List[Dict] = []
def reset(self):
self.reset_counters()
self.steps = []
def _make_result(self, name: str, found: bool, index: int, time_c: str, space_c: str,
arr_size: int, target: Any) -> Dict:
return {
'algorithm': name,
'found': found,
'index': index,
'time_complexity': time_c,
'space_complexity': space_c,
'array_size': arr_size,
'target': target,
'comparisons': self.comparisons,
'accesses': self.accesses,
'recursions': self.recursions,
}
@profile_algorithm
def linear_search(self, arr: List[Any], target: Any) -> Dict:
self.reset()
for i, val in enumerate(arr):
self.comparisons += 1
self.accesses += 1
if val == target:
return self._make_result('Linear Search', True, i, 'O(n)', 'O(1)', len(arr), target)
return self._make_result('Linear Search', False, -1, 'O(n)', 'O(1)', len(arr), target)
@profile_algorithm
def binary_search_iterative(self, arr: List[Any], target: Any) -> Dict:
self.reset()
left, right = 0, len(arr) - 1
while left <= right:
self.comparisons += 1
mid = (left + right) // 2
self.accesses += 1
if arr[mid] == target:
return self._make_result('Binary Search (Iterative)', True, mid, 'O(log n)', 'O(1)', len(arr), target)
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return self._make_result('Binary Search (Iterative)', False, -1, 'O(log n)', 'O(1)', len(arr), target)
@profile_algorithm
def binary_search_recursive(self, arr: List[Any], target: Any, left: int = 0, right: int = None, _is_outer: bool = True) -> Dict:
if right is None:
self.reset()
right = len(arr) - 1
if _is_outer:
self.recursions += 1
if left > right:
return self._make_result('Binary Search (Recursive)', False, -1, 'O(log n)', 'O(log n)', len(arr), target)
self.comparisons += 1
mid = (left + right) // 2
self.accesses += 1
if arr[mid] == target:
return self._make_result('Binary Search (Recursive)', True, mid, 'O(log n)', 'O(log n)', len(arr), target)
elif arr[mid] < target:
return self.binary_search_recursive(arr, target, mid + 1, right, _is_outer=False)
else:
return self.binary_search_recursive(arr, target, left, mid - 1, _is_outer=False)
@profile_algorithm
def jump_search(self, arr: List[Any], target: Any) -> Dict:
self.reset()
n = len(arr)
step = int(math.sqrt(n))
prev = 0
while prev < n and arr[min(step, n) - 1] < target:
self.comparisons += 1
self.accesses += 1
prev = step
step += int(math.sqrt(n))
if prev >= n:
return self._make_result('Jump Search', False, -1, 'O(√n)', 'O(1)', n, target)
while prev < min(step, n) and arr[prev] < target:
self.comparisons += 1
self.accesses += 1
prev += 1
self.accesses += 1
if prev < n and arr[prev] == target:
return self._make_result('Jump Search', True, prev, 'O(√n)', 'O(1)', n, target)
return self._make_result('Jump Search', False, -1, 'O(√n)', 'O(1)', n, target)
@profile_algorithm
def interpolation_search(self, arr: List[Any], target: Any) -> Dict:
self.reset()
left, right = 0, len(arr) - 1
while left <= right and target >= arr[left] and target <= arr[right]:
self.comparisons += 1
if left == right:
self.accesses += 1
if arr[left] == target:
return self._make_result('Interpolation Search', True, left, 'O(log log n) avg', 'O(1)', len(arr), target)
break
pos = left + int(((target - arr[left]) / (arr[right] - arr[left])) * (right - left))
self.accesses += 1
if arr[pos] == target:
return self._make_result('Interpolation Search', True, pos, 'O(log log n) avg', 'O(1)', len(arr), target)
elif arr[pos] < target:
left = pos + 1
else:
right = pos - 1
return self._make_result('Interpolation Search', False, -1, 'O(log log n) avg', 'O(1)', len(arr), target)
@profile_algorithm
def exponential_search(self, arr: List[Any], target: Any) -> Dict:
self.reset()
n = len(arr)
if n == 0:
return self._make_result('Exponential Search', False, -1, 'O(log n)', 'O(1)', 0, target)
self.accesses += 1
if arr[0] == target:
return self._make_result('Exponential Search', True, 0, 'O(log n)', 'O(1)', n, target)
bound = 1
while bound < n and arr[bound] <= target:
self.comparisons += 1
self.accesses += 1
bound *= 2
left = bound // 2
right = min(bound, n - 1)
while left <= right:
self.comparisons += 1
mid = (left + right) // 2
self.accesses += 1
if arr[mid] == target:
return self._make_result('Exponential Search', True, mid, 'O(log n)', 'O(1)', n, target)
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return self._make_result('Exponential Search', False, -1, 'O(log n)', 'O(1)', n, target)
@profile_algorithm
def ternary_search(self, arr: List[Any], target: Any) -> Dict:
self.reset()
left, right = 0, len(arr) - 1
while left <= right:
self.comparisons += 1
third = (right - left) // 3
mid1 = left + third
mid2 = right - third
self.accesses += 2
if arr[mid1] == target:
return self._make_result('Ternary Search', True, mid1, 'O(log₃ n)', 'O(1)', len(arr), target)
if arr[mid2] == target:
return self._make_result('Ternary Search', True, mid2, 'O(log₃ n)', 'O(1)', len(arr), target)
if target < arr[mid1]:
right = mid1 - 1
elif target > arr[mid2]:
left = mid2 + 1
else:
left = mid1 + 1
right = mid2 - 1
return self._make_result('Ternary Search', False, -1, 'O(log₃ n)', 'O(1)', len(arr), target)
@profile_algorithm
def fibonacci_search(self, arr: List[Any], target: Any) -> Dict:
self.reset()
n = len(arr)
fib2, fib1 = 0, 1
fib = fib1 + fib2
while fib < n:
fib2 = fib1
fib1 = fib
fib = fib1 + fib2
offset = -1
while fib > 1:
i = min(offset + fib2, n - 1)
self.accesses += 1
self.comparisons += 1
if arr[i] < target:
fib = fib1
fib1 = fib2
fib2 = fib - fib1
offset = i
elif arr[i] > target:
fib = fib2
fib1 = fib1 - fib2
fib2 = fib - fib1
else:
return self._make_result('Fibonacci Search', True, i, 'O(log n)', 'O(1)', n, target)
self.accesses += 1
if fib1 and offset + 1 < n and arr[offset + 1] == target:
return self._make_result('Fibonacci Search', True, offset + 1, 'O(log n)', 'O(1)', n, target)
return self._make_result('Fibonacci Search', False, -1, 'O(log n)', 'O(1)', n, target)
def compare_all(self, arr: List[Any], target: Any) -> List[Dict]:
"""Benchmark all searching algorithms"""
sorted_arr = sorted(arr)
algorithms = [
('Linear Search', self.linear_search),
('Binary Search (Iter)', self.binary_search_iterative),
('Binary Search (Rec)', self.binary_search_recursive),
('Jump Search', self.jump_search),
('Interpolation Search', self.interpolation_search),
('Exponential Search', self.exponential_search),
('Ternary Search', self.ternary_search),
('Fibonacci Search', self.fibonacci_search),
]
results = []
for name, algo in algorithms:
try:
res = algo(sorted_arr if name != 'Linear Search' else arr, target)
results.append({
'name': name,
'time_ms': res.get('execution_time_ms', 0),
'complexity': res.get('time_complexity', 'N/A'),
'found': res.get('found', False),
'index': res.get('index', -1),
'comparisons': res.get('comparisons', 0),
})
except Exception as e:
results.append({'name': name, 'error': str(e)})
return results