Skip to content

Commit d13b78a

Browse files
committed
feat(circular-linked-list): init circular linked list
1 parent 8b83c03 commit d13b78a

File tree

4 files changed

+182
-12
lines changed

4 files changed

+182
-12
lines changed

datastructures/linked_lists/__init__.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
1-
# coding=utf-8
1+
from typing import Any, Union, Optional, Generic, TypeVar
22
from abc import ABCMeta, abstractmethod
3-
from typing import Any, Union, Optional
43

54
from datastructures.linked_lists.exceptions import EmptyLinkedList
65

6+
T = TypeVar("T")
77

8-
class Node:
8+
9+
class Node(Generic[T]):
910
"""
1011
Node object in the Linked List
1112
"""
1213

1314
__metaclass__ = ABCMeta
1415

15-
def __init__(self, data=Optional[Any], next_=None, key=None):
16+
def __init__(self, data: Optional[T] = None, next_: Optional['Node[Generic[T]]'] = None, key: Any = None):
1617
self.data = data
17-
self.next: Optional[Node] = next_
18+
self.next = next_
1819
self.key = key
1920

20-
def __str__(self):
21+
def __str__(self) -> str:
2122
return f"Node({self.data})"
2223

23-
def __repr__(self):
24+
def __repr__(self) -> str:
2425
return f"Node({self.data})"
2526

26-
def __eq__(self, other: "Node"):
27+
def __eq__(self, other: "Node") -> bool:
2728
return self.data == other.data
2829

2930

30-
class LinkedList:
31+
class LinkedList(Generic[T]):
3132
"""
3233
The most basic LinkedList from which other types of Linked List will be subclassed
3334
"""
3435

3536
__metaclass__ = ABCMeta
36-
head: Optional[Node] = None
37+
head: Optional[Node[Generic[T]]] = None
3738

3839
def __init__(self):
3940
self.head = None
@@ -52,11 +53,11 @@ def __iter__(self):
5253

5354
@abstractmethod
5455
def __str__(self):
55-
raise NotImplementedError("Not Yet implemented")
56+
return "->".join([str(item) for item in self])
5657

5758
@abstractmethod
5859
def __repr__(self):
59-
raise NotImplementedError("Not Yet implemented")
60+
return "->".join([str(item) for item in self])
6061

6162
def __len__(self):
6263
"""
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
from typing import Optional, Any, Union
2+
3+
from datastructures.linked_lists import LinkedList, Node, T
4+
from .node import CircularNode
5+
6+
7+
class CircularLinkedList(LinkedList):
8+
head: Optional[CircularNode] = None
9+
10+
def __init__(self):
11+
super().__init__()
12+
13+
def __str__(self):
14+
return super().__str__()
15+
16+
def __repr__(self):
17+
return super().__repr__()
18+
19+
def __iter__(self):
20+
current = self.head
21+
while current:
22+
yield current.data
23+
# break out of the loop when the next node is back at the head node to avoid a continuous loop
24+
if current.next == self.head:
25+
break
26+
current = current.next
27+
28+
def append(self, data: T):
29+
"""
30+
Adds a new node to the end of this linked list. To maintain circular pointers where the last node points back
31+
to the head node, the pointer keeping track of the nodes as it traverses through the list checks to see if the
32+
next pointer equals the head node. If it is, the pointer exists the loop, otherwise this becomes an infinite
33+
loop. Once the pointer is at the end, the last node's next pointer is set to the new node and the new node's
34+
next pointer is set to the head node.
35+
If there is not head node, then the new node becomes the head node and it's next pointer points to itself.
36+
Args:
37+
data T: data to insert in the linked list
38+
"""
39+
new_node = CircularNode(value=data)
40+
if not self.head:
41+
self.head = new_node
42+
self.head.next = self.head
43+
else:
44+
new_node = CircularNode(value=data)
45+
current = self.head
46+
while current.next != self.head:
47+
current = current.next
48+
current.next = new_node
49+
new_node.next = self.head
50+
51+
def prepend(self, data):
52+
pass
53+
54+
def reverse(self):
55+
pass
56+
57+
def insert(self, node, pos):
58+
pass
59+
60+
def insert_after_node(self, prev: Any, data: Any):
61+
pass
62+
63+
def unshift(self, node):
64+
pass
65+
66+
def shift(self):
67+
pass
68+
69+
def pop(self) -> Optional[Node]:
70+
pass
71+
72+
def delete_node(self, node: Node):
73+
pass
74+
75+
def delete_node_at_position(self, position: int):
76+
pass
77+
78+
def delete_node_by_data(self, data: Any):
79+
pass
80+
81+
def delete_nodes_by_data(self, data: Any):
82+
pass
83+
84+
def delete_middle_node(self) -> Optional[Node]:
85+
pass
86+
87+
def display(self):
88+
pass
89+
90+
def display_forward(self):
91+
pass
92+
93+
def display_backward(self):
94+
pass
95+
96+
def alternate_split(self):
97+
pass
98+
99+
def is_palindrome(self) -> bool:
100+
pass
101+
102+
def pairwise_swap(self) -> Node:
103+
pass
104+
105+
def swap_nodes_at_kth_and_k_plus_1(self, k: int) -> Node:
106+
pass
107+
108+
def move_to_front(self, node: Node):
109+
pass
110+
111+
def move_tail_to_head(self):
112+
pass
113+
114+
def partition(self, data: Any) -> Union[Node, None]:
115+
pass
116+
117+
def remove_tail(self):
118+
pass
119+
120+
def remove_duplicates(self) -> Optional[Node]:
121+
pass
122+
123+
def rotate(self, k: int):
124+
pass
125+
126+
def reverse_groups(self, k: int):
127+
pass
128+
129+
def odd_even_list(self) -> Optional[Node]:
130+
pass
131+
132+
def maximum_pair_sum(self) -> int:
133+
pass
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from typing import Optional, Self
2+
from datastructures.linked_lists import Node, T
3+
4+
5+
class CircularNode(Node):
6+
"""
7+
CircularNode implementation in a circular linked list
8+
"""
9+
10+
def __init__(self, value: T, next_: Optional[Self] = None):
11+
super().__init__(value, next_)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import unittest
2+
from . import CircularLinkedList
3+
4+
5+
class CircularLinkedListAppendTestCase(unittest.TestCase):
6+
def test_1(self):
7+
"""should append a new node 7 to linked list [1,2,3,4,5,6] to become [1,2,3,4,5,6,7]"""
8+
data = [1, 2, 3, 4, 5, 6]
9+
expected = [1, 2, 3, 4, 5, 6, 7]
10+
linked_list = CircularLinkedList()
11+
12+
for d in data:
13+
linked_list.append(d)
14+
15+
linked_list.append(7)
16+
17+
actual_head = linked_list.head
18+
self.assertIsNotNone(actual_head)
19+
20+
self.assertEqual(1, actual_head.data)
21+
self.assertEqual(expected, list(linked_list))
22+
23+
24+
if __name__ == '__main__':
25+
unittest.main()

0 commit comments

Comments
 (0)