Skip to content

Commit 34cac9d

Browse files
committed
feat(searches): Add Floyd's Cycle-Finding Algorithm
Signed-off-by: Aditya Kumar <aditya.kumar60@infosys.com>
1 parent e2a78d4 commit 34cac9d

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

searches/floyds_cycle_finding.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""
2+
An implementation of Floyd's Cycle-Finding Algorithm.
3+
Also known as the "tortoise and the hare" algorithm.
4+
5+
This algorithm is used to detect a cycle in a sequence of iterated function values.
6+
It can also find the starting index and length of the cycle.
7+
8+
Wikipedia: https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare
9+
"""
10+
from typing import Any, Callable, Optional, Tuple
11+
12+
13+
def floyds_cycle_finding(
14+
f: Callable[[Any], Any], x0: Any
15+
) -> Optional[Tuple[int, int]]:
16+
"""
17+
Finds a cycle in the sequence of values generated by the function f.
18+
19+
Args:
20+
f: A function that takes a value and returns the next value in the sequence.
21+
x0: The starting value of the sequence.
22+
23+
Returns:
24+
A tuple containing the index of the first element of the cycle (mu)
25+
and the length of the cycle (lam), or None if no cycle is found.
26+
27+
Doctest examples:
28+
>>> # Example with a cycle
29+
>>> f = lambda x: (2 * x + 3) % 17
30+
>>> floyds_cycle_finding(f, 0)
31+
(0, 8)
32+
33+
>>> # Example with a different starting point and cycle
34+
>>> f = lambda x: [1, 2, 3, 4, 5, 3][x]
35+
>>> floyds_cycle_finding(f, 0)
36+
(2, 3)
37+
38+
>>> # Example with no cycle (sequence terminates)
39+
>>> nodes = {0: 1, 1: 2, 2: 3, 3: None}
40+
>>> f = lambda x: nodes.get(x)
41+
>>> floyds_cycle_finding(f, 0)
42+
43+
"""
44+
# Main phase of the algorithm: finding a repetition x_i = x_2i.
45+
# The hare moves twice as fast as the tortoise.
46+
tortoise = f(x0)
47+
hare = f(f(x0))
48+
while tortoise != hare:
49+
# If the hare reaches the end of the sequence, there is no cycle.
50+
if hare is None or f(hare) is None:
51+
return None
52+
tortoise = f(tortoise)
53+
hare = f(f(hare))
54+
55+
# At this point, the tortoise and hare have met.
56+
# Now, find the position of the first repetition.
57+
# The distance from the start to the cycle's beginning is mu.
58+
mu = 0
59+
tortoise = x0
60+
while tortoise != hare:
61+
tortoise = f(tortoise)
62+
hare = f(hare)
63+
mu += 1
64+
65+
# Finally, find the length of the cycle.
66+
# The hare moves one step at a time while the tortoise stays put.
67+
# The number of steps until they meet again is the cycle length (lam).
68+
lam = 1
69+
hare = f(tortoise)
70+
while tortoise != hare:
71+
hare = f(hare)
72+
lam += 1
73+
74+
return mu, lam
75+
76+
77+
if __name__ == "__main__":
78+
import doctest
79+
80+
doctest.testmod()

0 commit comments

Comments
 (0)