Skip to content

Commit 0dd6821

Browse files
committed
refactor(searches): Improve readability of Floyd's Cycle-Finding Algorithm
Signed-off-by: Aditya Kumar <aditya.kumar60@infosys.com>
1 parent a44a5fb commit 0dd6821

File tree

1 file changed

+30
-33
lines changed

1 file changed

+30
-33
lines changed

searches/floyds_cycle_finding.py

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,67 +7,64 @@
77
88
Wikipedia: https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare
99
"""
10+
from collections.abc import Callable
11+
from typing import Any
1012

11-
from typing import Any, Callable, Optional, Tuple
1213

13-
14-
def floyds_cycle_finding(f: Callable[[Any], Any], x0: Any) -> Optional[Tuple[int, int]]:
14+
def floyds_cycle_finding(
15+
successor_function: Callable[[Any], Any], start_value: Any
16+
) -> tuple[int, int] | None:
1517
"""
16-
Finds a cycle in the sequence of values generated by the function f.
18+
Finds a cycle in the sequence of values generated by the successor function.
1719
1820
Args:
19-
f: A function that takes a value and returns the next value in the sequence.
20-
x0: The starting value of the sequence.
21+
successor_function: A function that takes a value and returns the next value.
22+
start_value: The starting value of the sequence.
2123
2224
Returns:
2325
A tuple containing the index of the first element of the cycle (mu)
2426
and the length of the cycle (lam), or None if no cycle is found.
2527
2628
Doctest examples:
27-
>>> # Example with a cycle
28-
>>> f = lambda x: (2 * x + 3) % 17
29-
>>> floyds_cycle_finding(f, 0)
29+
>>> # Example with a mathematical sequence
30+
>>> sequence_func = lambda x: (2 * x + 3) % 17
31+
>>> floyds_cycle_finding(sequence_func, 0)
3032
(0, 8)
3133
32-
>>> # Example with a different starting point and cycle
33-
>>> f = lambda x: [1, 2, 3, 4, 5, 3][x]
34-
>>> floyds_cycle_finding(f, 0)
34+
>>> # Example with a list acting as a sequence
35+
>>> get_next_item = lambda x: [1, 2, 3, 4, 5, 3][x]
36+
>>> floyds_cycle_finding(get_next_item, 0)
3537
(2, 3)
3638
37-
>>> # Example with no cycle (sequence terminates)
38-
>>> nodes = {0: 1, 1: 2, 2: 3, 3: None}
39-
>>> f = lambda x: nodes.get(x)
40-
>>> floyds_cycle_finding(f, 0)
39+
>>> # Example with a graph-like structure (no cycle)
40+
>>> get_next_node = lambda x: {0: 1, 1: 2, 2: 3, 3: None}.get(x)
41+
>>> floyds_cycle_finding(get_next_node, 0)
4142
4243
"""
43-
# Main phase of the algorithm: finding a repetition x_i = x_2i.
44+
# Main phase: finding a repetition x_i = x_2i.
4445
# The hare moves twice as fast as the tortoise.
45-
tortoise = f(x0)
46-
hare = f(f(x0))
46+
tortoise = successor_function(start_value)
47+
hare = successor_function(successor_function(start_value))
4748
while tortoise != hare:
4849
# If the hare reaches the end of the sequence, there is no cycle.
49-
if hare is None or f(hare) is None:
50+
if hare is None or successor_function(hare) is None:
5051
return None
51-
tortoise = f(tortoise)
52-
hare = f(f(hare))
52+
tortoise = successor_function(tortoise)
53+
hare = successor_function(successor_function(hare))
5354

54-
# At this point, the tortoise and hare have met.
55-
# Now, find the position of the first repetition.
56-
# The distance from the start to the cycle's beginning is mu.
55+
# Phase 2: find the position of the first repetition (mu).
5756
mu = 0
58-
tortoise = x0
57+
tortoise = start_value
5958
while tortoise != hare:
60-
tortoise = f(tortoise)
61-
hare = f(hare)
59+
tortoise = successor_function(tortoise)
60+
hare = successor_function(hare)
6261
mu += 1
6362

64-
# Finally, find the length of the cycle.
65-
# The hare moves one step at a time while the tortoise stays put.
66-
# The number of steps until they meet again is the cycle length (lam).
63+
# Phase 3: find the length of the cycle (lam).
6764
lam = 1
68-
hare = f(tortoise)
65+
hare = successor_function(tortoise)
6966
while tortoise != hare:
70-
hare = f(hare)
67+
hare = successor_function(hare)
7168
lam += 1
7269

7370
return mu, lam

0 commit comments

Comments
 (0)