Skip to content

Commit

Permalink
Adds operations for circular linked list (TheAlgorithms#1584)
Browse files Browse the repository at this point in the history
* Adds, append, len, print operations for circular linked list

* Adds, prepend support

* Adds, delete from front of the list

* Adds, delete_rear support

* Adds, method documentations

* Adds, type checking and doctests

* Updates doctest for delete ops

* Addressing requested changes

* Removes unused import

* Fixes failing doctests

* Minor modifications...
  • Loading branch information
onlinejudge95 authored and cclauss committed Nov 19, 2019
1 parent 2565797 commit c57c4ca
Showing 1 changed file with 186 additions and 0 deletions.
186 changes: 186 additions & 0 deletions data_structures/linked_list/circular_linked_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
from typing import Any


class Node:
"""
Class to represent a single node.
Each node has following attributes
* data
* next_ptr
"""

def __init__(self, data: Any):
self.data = data
self.next_ptr = None


class CircularLinkedList:
"""
Class to represent the CircularLinkedList.
CircularLinkedList has following attributes.
* head
* length
"""

def __init__(self):
self.head = None
self.length = 0

def __len__(self) -> int:
"""
Dunder method to return length of the CircularLinkedList
>>> cll = CircularLinkedList()
>>> len(cll)
0
>>> cll.append(1)
>>> len(cll)
1
"""
return self.length

def __str__(self) -> str:
"""
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]
current_node = current_node.next_ptr

while current_node != self.head:
results.append(current_node.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

new_node = Node(data)
new_node.next_ptr = new_node

if current_node:
while current_node.next_ptr != self.head:
current_node = current_node.next_ptr

current_node.next_ptr = new_node
new_node.next_ptr = self.head
else:
self.head = new_node

self.length += 1

def prepend(self, data: Any) -> None:
"""
Adds a ndoe 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)
new_node.next_ptr = new_node

if current_node:
while current_node.next_ptr != self.head:
current_node = current_node.next_ptr

current_node.next_ptr = new_node
new_node.next_ptr = self.head

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>
"""
if not self.head:
raise IndexError("Deleting from an empty list")

current_node = self.head

if current_node.next_ptr == current_node:
self.head, self.length = None, 0
else:
while current_node.next_ptr != self.head:
current_node = current_node.next_ptr

current_node.next_ptr = self.head.next_ptr
self.head = self.head.next_ptr

self.length -= 1

def delete_rear(self) -> None:
"""
Removes the last node from the CircularLinkedList
>>> 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>
"""
if not self.head:
raise IndexError("Deleting from an empty list")

temp_node, current_node = self.head, self.head

if current_node.next_ptr == current_node:
self.head, self.length = None, 0
else:
while current_node.next_ptr != self.head:
temp_node = current_node
current_node = current_node.next_ptr

temp_node.next_ptr = current_node.next_ptr

self.length -= 1


if __name__ == "__main__":
import doctest

doctest.testmod()

0 comments on commit c57c4ca

Please sign in to comment.