Contains loops.py add (#2442)

* added an algorithm which checks a linked list for loops and returns true if one is found

* added doctests and clarified meaning of loop

* Define Node.__iter__()

* Update and rename has_loop.py to has_duplicate_data.py

* Update has_duplicate_data.py

* Update has_duplicate_data.py

* Update and rename has_duplicate_data.py to has_loop.py

* Update has_loop.py

Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
kanthuc 2020-09-18 13:53:50 -07:00 committed by GitHub
parent dc415ec14a
commit ecac7b0973
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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