Skip to content

Commit 7f48bb8

Browse files
realDuYuanChaogithub-actionscclauss
authored
Updated circular_linked_list (TheAlgorithms#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 <[email protected]> * 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 <[email protected]>
1 parent db0db01 commit 7f48bb8

File tree

1 file changed

+113
-177
lines changed

1 file changed

+113
-177
lines changed

data_structures/linked_list/circular_linked_list.py

+113-177
Original file line numberDiff line numberDiff line change
@@ -2,201 +2,137 @@
22

33

44
class Node:
5-
"""
6-
Class to represent a single node.
7-
8-
Each node has following attributes
9-
* data
10-
* next_ptr
11-
"""
12-
135
def __init__(self, data: Any):
146
self.data = data
15-
self.next_ptr = None
7+
self.next = None
168

179

1810
class CircularLinkedList:
19-
"""
20-
Class to represent the CircularLinkedList.
21-
22-
CircularLinkedList has following attributes.
23-
* head
24-
* length
25-
"""
26-
2711
def __init__(self):
2812
self.head = None
29-
self.length = 0
13+
self.tail = None
3014

31-
def __len__(self) -> int:
32-
"""
33-
Dunder method to return length of the CircularLinkedList
34-
>>> cll = CircularLinkedList()
35-
>>> len(cll)
36-
0
37-
>>> cll.append(1)
38-
>>> len(cll)
39-
1
40-
>>> cll.prepend(0)
41-
>>> len(cll)
42-
2
43-
>>> cll.delete_front()
44-
>>> len(cll)
45-
1
46-
>>> cll.delete_rear()
47-
>>> len(cll)
48-
0
49-
"""
50-
return self.length
51-
52-
def __str__(self) -> str:
53-
"""
54-
Dunder method to represent the string representation of the CircularLinkedList
55-
>>> cll = CircularLinkedList()
56-
>>> print(cll)
57-
Empty linked list
58-
>>> cll.append(1)
59-
>>> cll.append(2)
60-
>>> print(cll)
61-
<Node data=1> => <Node data=2>
62-
"""
63-
current_node = self.head
64-
if not current_node:
65-
return "Empty linked list"
66-
67-
results = [current_node.data]
68-
current_node = current_node.next_ptr
69-
70-
while current_node != self.head:
71-
results.append(current_node.data)
72-
current_node = current_node.next_ptr
73-
74-
return " => ".join(f"<Node data={result}>" for result in results)
75-
76-
def append(self, data: Any) -> None:
77-
"""
78-
Adds a node with given data to the end of the CircularLinkedList
79-
>>> cll = CircularLinkedList()
80-
>>> cll.append(1)
81-
>>> print(f"{len(cll)}: {cll}")
82-
1: <Node data=1>
83-
>>> cll.append(2)
84-
>>> print(f"{len(cll)}: {cll}")
85-
2: <Node data=1> => <Node data=2>
86-
"""
87-
current_node = self.head
88-
89-
new_node = Node(data)
90-
new_node.next_ptr = new_node
15+
def __iter__(self):
16+
node = self.head
17+
while self.head:
18+
yield node.data
19+
node = node.next
20+
if node == self.head:
21+
break
9122

92-
if current_node:
93-
while current_node.next_ptr != self.head:
94-
current_node = current_node.next_ptr
23+
def __len__(self) -> int:
24+
return len(tuple(iter(self)))
9525

96-
current_node.next_ptr = new_node
97-
new_node.next_ptr = self.head
98-
else:
99-
self.head = new_node
26+
def __repr__(self):
27+
return "->".join(str(item) for item in iter(self))
10028

101-
self.length += 1
29+
def insert_tail(self, data: Any) -> None:
30+
self.insert_nth(len(self), data)
10231

103-
def prepend(self, data: Any) -> None:
104-
"""
105-
Adds a node with given data to the front of the CircularLinkedList
106-
>>> cll = CircularLinkedList()
107-
>>> cll.prepend(1)
108-
>>> cll.prepend(2)
109-
>>> print(f"{len(cll)}: {cll}")
110-
2: <Node data=2> => <Node data=1>
111-
"""
112-
current_node = self.head
32+
def insert_head(self, data: Any) -> None:
33+
self.insert_nth(0, data)
11334

35+
def insert_nth(self, index: int, data: Any) -> None:
36+
if index < 0 or index > len(self):
37+
raise IndexError("list index out of range.")
11438
new_node = Node(data)
115-
new_node.next_ptr = new_node
116-
117-
if current_node:
118-
while current_node.next_ptr != self.head:
119-
current_node = current_node.next_ptr
120-
121-
current_node.next_ptr = new_node
122-
new_node.next_ptr = self.head
123-
124-
self.head = new_node
125-
self.length += 1
126-
127-
def delete_front(self) -> None:
128-
"""
129-
Removes the 1st node from the CircularLinkedList
130-
>>> cll = CircularLinkedList()
131-
>>> cll.delete_front()
132-
Traceback (most recent call last):
133-
...
134-
IndexError: Deleting from an empty list
135-
>>> cll.append(1)
136-
>>> cll.append(2)
137-
>>> print(f"{len(cll)}: {cll}")
138-
2: <Node data=1> => <Node data=2>
139-
>>> cll.delete_front()
140-
>>> print(f"{len(cll)}: {cll}")
141-
1: <Node data=2>
142-
>>> cll.delete_front()
143-
>>> print(f"{len(cll)}: {cll}")
144-
0: Empty linked list
145-
"""
146-
if not self.head:
147-
raise IndexError("Deleting from an empty list")
148-
149-
current_node = self.head
150-
151-
if current_node.next_ptr == current_node:
152-
self.head = None
39+
if self.head is None:
40+
new_node.next = new_node # first node points itself
41+
self.tail = self.head = new_node
42+
elif index == 0: # insert at head
43+
new_node.next = self.head
44+
self.head = self.tail.next = new_node
15345
else:
154-
while current_node.next_ptr != self.head:
155-
current_node = current_node.next_ptr
156-
157-
current_node.next_ptr = self.head.next_ptr
158-
self.head = self.head.next_ptr
159-
160-
self.length -= 1
161-
if not self.head:
162-
assert self.length == 0
163-
164-
def delete_rear(self) -> None:
165-
"""
166-
Removes the last node from the CircularLinkedList
167-
>>> cll = CircularLinkedList()
168-
>>> cll.delete_rear()
169-
Traceback (most recent call last):
170-
...
171-
IndexError: Deleting from an empty list
172-
>>> cll.append(1)
173-
>>> cll.append(2)
174-
>>> print(f"{len(cll)}: {cll}")
175-
2: <Node data=1> => <Node data=2>
176-
>>> cll.delete_rear()
177-
>>> print(f"{len(cll)}: {cll}")
178-
1: <Node data=1>
179-
>>> cll.delete_rear()
180-
>>> print(f"{len(cll)}: {cll}")
181-
0: Empty linked list
182-
"""
183-
if not self.head:
184-
raise IndexError("Deleting from an empty list")
185-
186-
temp_node, current_node = self.head, self.head
187-
188-
if current_node.next_ptr == current_node:
189-
self.head = None
46+
temp = self.head
47+
for _ in range(index - 1):
48+
temp = temp.next
49+
new_node.next = temp.next
50+
temp.next = new_node
51+
if index == len(self) - 1: # insert at tail
52+
self.tail = new_node
53+
54+
def delete_front(self):
55+
return self.delete_nth(0)
56+
57+
def delete_tail(self) -> None:
58+
return self.delete_nth(len(self) - 1)
59+
60+
def delete_nth(self, index: int = 0):
61+
if not 0 <= index < len(self):
62+
raise IndexError("list index out of range.")
63+
delete_node = self.head
64+
if self.head == self.tail: # just one node
65+
self.head = self.tail = None
66+
elif index == 0: # delete head node
67+
self.tail.next = self.tail.next.next
68+
self.head = self.head.next
19069
else:
191-
while current_node.next_ptr != self.head:
192-
temp_node = current_node
193-
current_node = current_node.next_ptr
70+
temp = self.head
71+
for _ in range(index - 1):
72+
temp = temp.next
73+
delete_node = temp.next
74+
temp.next = temp.next.next
75+
if index == len(self) - 1: # delete at tail
76+
self.tail = temp
77+
return delete_node.data
78+
79+
def is_empty(self):
80+
return len(self) == 0
19481

195-
temp_node.next_ptr = current_node.next_ptr
19682

197-
self.length -= 1
198-
if not self.head:
199-
assert self.length == 0
83+
def test_circular_linked_list() -> None:
84+
"""
85+
>>> test_circular_linked_list()
86+
"""
87+
circular_linked_list = CircularLinkedList()
88+
assert len(circular_linked_list) == 0
89+
assert circular_linked_list.is_empty() is True
90+
assert str(circular_linked_list) == ""
91+
92+
try:
93+
circular_linked_list.delete_front()
94+
assert False # This should not happen
95+
except IndexError:
96+
assert True # This should happen
97+
98+
try:
99+
circular_linked_list.delete_tail()
100+
assert False # This should not happen
101+
except IndexError:
102+
assert True # This should happen
103+
104+
try:
105+
circular_linked_list.delete_nth(-1)
106+
assert False
107+
except IndexError:
108+
assert True
109+
110+
try:
111+
circular_linked_list.delete_nth(0)
112+
assert False
113+
except IndexError:
114+
assert True
115+
116+
assert circular_linked_list.is_empty() is True
117+
for i in range(5):
118+
assert len(circular_linked_list) == i
119+
circular_linked_list.insert_nth(i, i + 1)
120+
assert str(circular_linked_list) == "->".join(str(i) for i in range(1, 6))
121+
122+
circular_linked_list.insert_tail(6)
123+
assert str(circular_linked_list) == "->".join(str(i) for i in range(1, 7))
124+
circular_linked_list.insert_head(0)
125+
assert str(circular_linked_list) == "->".join(str(i) for i in range(0, 7))
126+
127+
assert circular_linked_list.delete_front() == 0
128+
assert circular_linked_list.delete_tail() == 6
129+
assert str(circular_linked_list) == "->".join(str(i) for i in range(1, 6))
130+
assert circular_linked_list.delete_nth(2) == 3
131+
132+
circular_linked_list.insert_nth(2, 3)
133+
assert str(circular_linked_list) == "->".join(str(i) for i in range(1, 6))
134+
135+
assert circular_linked_list.is_empty() is False
200136

201137

202138
if __name__ == "__main__":

0 commit comments

Comments
 (0)