Updated circular_linked_list (#2483)

* Updated circular_linked_list

* fixup! Format Python code with psf/black push

* Update data_structures/linked_list/circular_linked_list.py

Co-authored-by: Christian Clauss <cclauss@me.com>

* updating DIRECTORY.md

* delete print_list()

* test is_empty()

* test is_empty return False

* fixup! Format Python code with psf/black push

* fixed indentation

* fixup! Format Python code with psf/black push

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
Du Yuanchao 2020-09-26 22:57:09 +08:00 committed by GitHub
parent db0db01d87
commit 7f48bb8c95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -2,201 +2,137 @@ from typing import Any
class Node: class Node:
"""
Class to represent a single node.
Each node has following attributes
* data
* next_ptr
"""
def __init__(self, data: Any): def __init__(self, data: Any):
self.data = data self.data = data
self.next_ptr = None self.next = None
class CircularLinkedList: class CircularLinkedList:
"""
Class to represent the CircularLinkedList.
CircularLinkedList has following attributes.
* head
* length
"""
def __init__(self): def __init__(self):
self.head = None self.head = None
self.length = 0 self.tail = None
def __iter__(self):
node = self.head
while self.head:
yield node.data
node = node.next
if node == self.head:
break
def __len__(self) -> int: def __len__(self) -> int:
""" return len(tuple(iter(self)))
Dunder method to return length of the CircularLinkedList
>>> cll = CircularLinkedList()
>>> len(cll)
0
>>> cll.append(1)
>>> len(cll)
1
>>> cll.prepend(0)
>>> len(cll)
2
>>> cll.delete_front()
>>> len(cll)
1
>>> cll.delete_rear()
>>> len(cll)
0
"""
return self.length
def __str__(self) -> str: def __repr__(self):
""" return "->".join(str(item) for item in iter(self))
Dunder method to represent the string representation of the CircularLinkedList
>>> cll = CircularLinkedList()
>>> print(cll)
Empty linked list
>>> cll.append(1)
>>> cll.append(2)
>>> print(cll)
<Node data=1> => <Node data=2>
"""
current_node = self.head
if not current_node:
return "Empty linked list"
results = [current_node.data] def insert_tail(self, data: Any) -> None:
current_node = current_node.next_ptr self.insert_nth(len(self), data)
while current_node != self.head: def insert_head(self, data: Any) -> None:
results.append(current_node.data) self.insert_nth(0, data)
current_node = current_node.next_ptr
return " => ".join(f"<Node data={result}>" for result in results)
def append(self, data: Any) -> None:
"""
Adds a node with given data to the end of the CircularLinkedList
>>> cll = CircularLinkedList()
>>> cll.append(1)
>>> print(f"{len(cll)}: {cll}")
1: <Node data=1>
>>> cll.append(2)
>>> print(f"{len(cll)}: {cll}")
2: <Node data=1> => <Node data=2>
"""
current_node = self.head
def insert_nth(self, index: int, data: Any) -> None:
if index < 0 or index > len(self):
raise IndexError("list index out of range.")
new_node = Node(data) new_node = Node(data)
new_node.next_ptr = new_node if self.head is None:
new_node.next = new_node # first node points itself
if current_node: self.tail = self.head = new_node
while current_node.next_ptr != self.head: elif index == 0: # insert at head
current_node = current_node.next_ptr new_node.next = self.head
self.head = self.tail.next = new_node
current_node.next_ptr = new_node
new_node.next_ptr = self.head
else: else:
self.head = new_node temp = self.head
for _ in range(index - 1):
temp = temp.next
new_node.next = temp.next
temp.next = new_node
if index == len(self) - 1: # insert at tail
self.tail = new_node
self.length += 1 def delete_front(self):
return self.delete_nth(0)
def prepend(self, data: Any) -> None: def delete_tail(self) -> None:
""" return self.delete_nth(len(self) - 1)
Adds a node with given data to the front of the CircularLinkedList
>>> cll = CircularLinkedList()
>>> cll.prepend(1)
>>> cll.prepend(2)
>>> print(f"{len(cll)}: {cll}")
2: <Node data=2> => <Node data=1>
"""
current_node = self.head
new_node = Node(data) def delete_nth(self, index: int = 0):
new_node.next_ptr = new_node if not 0 <= index < len(self):
raise IndexError("list index out of range.")
if current_node: delete_node = self.head
while current_node.next_ptr != self.head: if self.head == self.tail: # just one node
current_node = current_node.next_ptr self.head = self.tail = None
elif index == 0: # delete head node
current_node.next_ptr = new_node self.tail.next = self.tail.next.next
new_node.next_ptr = self.head self.head = self.head.next
self.head = new_node
self.length += 1
def delete_front(self) -> None:
"""
Removes the 1st node from the CircularLinkedList
>>> cll = CircularLinkedList()
>>> cll.delete_front()
Traceback (most recent call last):
...
IndexError: Deleting from an empty list
>>> cll.append(1)
>>> cll.append(2)
>>> print(f"{len(cll)}: {cll}")
2: <Node data=1> => <Node data=2>
>>> cll.delete_front()
>>> print(f"{len(cll)}: {cll}")
1: <Node data=2>
>>> cll.delete_front()
>>> print(f"{len(cll)}: {cll}")
0: Empty linked list
"""
if not self.head:
raise IndexError("Deleting from an empty list")
current_node = self.head
if current_node.next_ptr == current_node:
self.head = None
else: else:
while current_node.next_ptr != self.head: temp = self.head
current_node = current_node.next_ptr for _ in range(index - 1):
temp = temp.next
delete_node = temp.next
temp.next = temp.next.next
if index == len(self) - 1: # delete at tail
self.tail = temp
return delete_node.data
current_node.next_ptr = self.head.next_ptr def is_empty(self):
self.head = self.head.next_ptr return len(self) == 0
self.length -= 1
if not self.head:
assert self.length == 0
def delete_rear(self) -> None: def test_circular_linked_list() -> None:
""" """
Removes the last node from the CircularLinkedList >>> test_circular_linked_list()
>>> cll = CircularLinkedList()
>>> cll.delete_rear()
Traceback (most recent call last):
...
IndexError: Deleting from an empty list
>>> cll.append(1)
>>> cll.append(2)
>>> print(f"{len(cll)}: {cll}")
2: <Node data=1> => <Node data=2>
>>> cll.delete_rear()
>>> print(f"{len(cll)}: {cll}")
1: <Node data=1>
>>> cll.delete_rear()
>>> print(f"{len(cll)}: {cll}")
0: Empty linked list
""" """
if not self.head: circular_linked_list = CircularLinkedList()
raise IndexError("Deleting from an empty list") assert len(circular_linked_list) == 0
assert circular_linked_list.is_empty() is True
assert str(circular_linked_list) == ""
temp_node, current_node = self.head, self.head try:
circular_linked_list.delete_front()
assert False # This should not happen
except IndexError:
assert True # This should happen
if current_node.next_ptr == current_node: try:
self.head = None circular_linked_list.delete_tail()
else: assert False # This should not happen
while current_node.next_ptr != self.head: except IndexError:
temp_node = current_node assert True # This should happen
current_node = current_node.next_ptr
temp_node.next_ptr = current_node.next_ptr try:
circular_linked_list.delete_nth(-1)
assert False
except IndexError:
assert True
self.length -= 1 try:
if not self.head: circular_linked_list.delete_nth(0)
assert self.length == 0 assert False
except IndexError:
assert True
assert circular_linked_list.is_empty() is True
for i in range(5):
assert len(circular_linked_list) == i
circular_linked_list.insert_nth(i, i + 1)
assert str(circular_linked_list) == "->".join(str(i) for i in range(1, 6))
circular_linked_list.insert_tail(6)
assert str(circular_linked_list) == "->".join(str(i) for i in range(1, 7))
circular_linked_list.insert_head(0)
assert str(circular_linked_list) == "->".join(str(i) for i in range(0, 7))
assert circular_linked_list.delete_front() == 0
assert circular_linked_list.delete_tail() == 6
assert str(circular_linked_list) == "->".join(str(i) for i in range(1, 6))
assert circular_linked_list.delete_nth(2) == 3
circular_linked_list.insert_nth(2, 3)
assert str(circular_linked_list) == "->".join(str(i) for i in range(1, 6))
assert circular_linked_list.is_empty() is False
if __name__ == "__main__": if __name__ == "__main__":