-
-
Notifications
You must be signed in to change notification settings - Fork 46.8k
Add Floyd's Cycle Detection Algorithm #10833
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
tianyizheng02
merged 4 commits into
TheAlgorithms:master
from
aqib-m31:floyds_cycle_detection_algorithm
Oct 23, 2023
Merged
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
""" | ||
Floyd's cycle detection algorithm is a popular algorithm used to detect cycles | ||
in a linked list. It uses two pointers, a slow pointer and a fast pointer, | ||
to traverse the linked list. The slow pointer moves one node at a time while the fast | ||
pointer moves two nodes at a time. If there is a cycle in the linked list, | ||
the fast pointer will eventually catch up to the slow pointer and they will | ||
meet at the same node. If there is no cycle, the fast pointer will reach the end of | ||
the linked list and the algorithm will terminate. | ||
|
||
For more information: https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare | ||
""" | ||
|
||
from collections.abc import Iterator | ||
from dataclasses import dataclass | ||
from typing import Any, Self | ||
|
||
|
||
@dataclass | ||
class Node: | ||
""" | ||
A class representing a node in a singly linked list. | ||
""" | ||
|
||
data: Any | ||
next_node: Self | None = None | ||
|
||
|
||
@dataclass | ||
class LinkedList: | ||
""" | ||
A class representing a singly linked list. | ||
""" | ||
|
||
head: Node | None = None | ||
|
||
def __iter__(self) -> Iterator: | ||
""" | ||
Iterates through the linked list. | ||
|
||
Returns: | ||
Iterator: An iterator over the linked list. | ||
|
||
Examples: | ||
>>> linked_list = LinkedList() | ||
>>> list(linked_list) | ||
[] | ||
>>> linked_list.add_node(1) | ||
>>> tuple(linked_list) | ||
(1,) | ||
""" | ||
node = self.head | ||
while node: | ||
yield node.data | ||
node = node.next_node | ||
|
||
def add_node(self, data: Any) -> None: | ||
""" | ||
Adds a new node to the end of the linked list. | ||
|
||
Args: | ||
data (Any): The data to be stored in the new node. | ||
""" | ||
new_node = Node(data) | ||
|
||
if self.head is None: | ||
self.head = new_node | ||
return | ||
|
||
current_node = self.head | ||
while current_node.next_node is not None: | ||
current_node = current_node.next_node | ||
|
||
current_node.next_node = new_node | ||
|
||
def detect_cycle(self) -> bool: | ||
""" | ||
Detects if there is a cycle in the linked list using | ||
Floyd's cycle detection algorithm. | ||
|
||
Returns: | ||
bool: True if there is a cycle, False otherwise. | ||
|
||
Examples: | ||
>>> linked_list = LinkedList() | ||
>>> linked_list.add_node(1) | ||
>>> linked_list.add_node(2) | ||
>>> linked_list.add_node(3) | ||
>>> linked_list.add_node(4) | ||
|
||
>>> linked_list.detect_cycle() | ||
False | ||
|
||
# Create a cycle in the linked list | ||
>>> linked_list.head.next_node.next_node.next_node = linked_list.head.next_node | ||
|
||
>>> linked_list.detect_cycle() | ||
True | ||
""" | ||
if self.head is None: | ||
return False | ||
|
||
slow_pointer: Node | None = self.head | ||
fast_pointer: Node | None = self.head | ||
|
||
while fast_pointer is not None and fast_pointer.next_node is not None: | ||
slow_pointer = slow_pointer.next_node if slow_pointer else None | ||
fast_pointer = fast_pointer.next_node.next_node | ||
if slow_pointer == fast_pointer: | ||
return True | ||
|
||
return False | ||
|
||
|
||
if __name__ == "__main__": | ||
import doctest | ||
|
||
doctest.testmod() | ||
|
||
linked_list = LinkedList() | ||
linked_list.add_node(1) | ||
linked_list.add_node(2) | ||
linked_list.add_node(3) | ||
linked_list.add_node(4) | ||
|
||
# Create a cycle in the linked list | ||
# It first checks if the head, next_node, and next_node.next_node attributes of the | ||
# linked list are not None to avoid any potential type errors. | ||
if ( | ||
linked_list.head | ||
and linked_list.head.next_node | ||
and linked_list.head.next_node.next_node | ||
): | ||
linked_list.head.next_node.next_node.next_node = linked_list.head.next_node | ||
|
||
has_cycle = linked_list.detect_cycle() | ||
print(has_cycle) # Output: True |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.