Python/searches/fibonacci_search.py
pre-commit-ci[bot] bc8df6de31
[pre-commit.ci] pre-commit autoupdate (#11322)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.2.2 → v0.3.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.2.2...v0.3.2)
- [github.com/pre-commit/mirrors-mypy: v1.8.0 → v1.9.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.8.0...v1.9.0)

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-03-13 07:52:41 +01:00

134 lines
2.9 KiB
Python

"""
This is pure Python implementation of fibonacci search.
Resources used:
https://en.wikipedia.org/wiki/Fibonacci_search_technique
For doctests run following command:
python3 -m doctest -v fibonacci_search.py
For manual testing run:
python3 fibonacci_search.py
"""
from functools import lru_cache
@lru_cache
def fibonacci(k: int) -> int:
"""Finds fibonacci number in index k.
Parameters
----------
k :
Index of fibonacci.
Returns
-------
int
Fibonacci number in position k.
>>> fibonacci(0)
0
>>> fibonacci(2)
1
>>> fibonacci(5)
5
>>> fibonacci(15)
610
>>> fibonacci('a')
Traceback (most recent call last):
TypeError: k must be an integer.
>>> fibonacci(-5)
Traceback (most recent call last):
ValueError: k integer must be greater or equal to zero.
"""
if not isinstance(k, int):
raise TypeError("k must be an integer.")
if k < 0:
raise ValueError("k integer must be greater or equal to zero.")
if k == 0:
return 0
elif k == 1:
return 1
else:
return fibonacci(k - 1) + fibonacci(k - 2)
def fibonacci_search(arr: list, val: int) -> int:
"""A pure Python implementation of a fibonacci search algorithm.
Parameters
----------
arr
List of sorted elements.
val
Element to search in list.
Returns
-------
int
The index of the element in the array.
-1 if the element is not found.
>>> fibonacci_search([4, 5, 6, 7], 4)
0
>>> fibonacci_search([4, 5, 6, 7], -10)
-1
>>> fibonacci_search([-18, 2], -18)
0
>>> fibonacci_search([5], 5)
0
>>> fibonacci_search(['a', 'c', 'd'], 'c')
1
>>> fibonacci_search(['a', 'c', 'd'], 'f')
-1
>>> fibonacci_search([], 1)
-1
>>> fibonacci_search([.1, .4 , 7], .4)
1
>>> fibonacci_search([], 9)
-1
>>> fibonacci_search(list(range(100)), 63)
63
>>> fibonacci_search(list(range(100)), 99)
99
>>> fibonacci_search(list(range(-100, 100, 3)), -97)
1
>>> fibonacci_search(list(range(-100, 100, 3)), 0)
-1
>>> fibonacci_search(list(range(-100, 100, 5)), 0)
20
>>> fibonacci_search(list(range(-100, 100, 5)), 95)
39
"""
len_list = len(arr)
# Find m such that F_m >= n where F_i is the i_th fibonacci number.
i = 0
while True:
if fibonacci(i) >= len_list:
fibb_k = i
break
i += 1
offset = 0
while fibb_k > 0:
index_k = min(
offset + fibonacci(fibb_k - 1), len_list - 1
) # Prevent out of range
item_k_1 = arr[index_k]
if item_k_1 == val:
return index_k
elif val < item_k_1:
fibb_k -= 1
elif val > item_k_1:
offset += fibonacci(fibb_k - 1)
fibb_k -= 2
else:
return -1
if __name__ == "__main__":
import doctest
doctest.testmod()