diff --git a/data_structures/linked_list/has_loop.py b/data_structures/linked_list/has_loop.py new file mode 100644 index 000000000000..405ece7e27c8 --- /dev/null +++ b/data_structures/linked_list/has_loop.py @@ -0,0 +1,60 @@ +from typing import Any + + +class ContainsLoopError(Exception): + pass + + +class Node: + def __init__(self, data: Any) -> None: + self.data = data + self.next_node = None + + def __iter__(self): + node = self + visited = [] + while node: + if node in visited: + raise ContainsLoopError + visited.append(node) + yield node.data + node = node.next_node + + @property + def has_loop(self) -> bool: + """ + A loop is when the exact same Node appears more than once in a linked list. + >>> root_node = Node(1) + >>> root_node.next_node = Node(2) + >>> root_node.next_node.next_node = Node(3) + >>> root_node.next_node.next_node.next_node = Node(4) + >>> root_node.has_loop + False + >>> root_node.next_node.next_node.next_node = root_node.next_node + >>> root_node.has_loop + True + """ + try: + list(self) + return False + except ContainsLoopError: + return True + + +if __name__ == "__main__": + root_node = Node(1) + root_node.next_node = Node(2) + root_node.next_node.next_node = Node(3) + root_node.next_node.next_node.next_node = Node(4) + print(root_node.has_loop) # False + root_node.next_node.next_node.next_node = root_node.next_node + print(root_node.has_loop) # True + + root_node = Node(5) + root_node.next_node = Node(6) + root_node.next_node.next_node = Node(5) + root_node.next_node.next_node.next_node = Node(6) + print(root_node.has_loop) # False + + root_node = Node(1) + print(root_node.has_loop) # False