1
1
from __future__ import annotations
2
-
3
2
from collections .abc import Iterator
4
3
from dataclasses import dataclass
5
4
from typing import Any
@@ -17,142 +16,81 @@ class CircularLinkedList:
17
16
tail : Node | None = None # Reference to the tail (last node)
18
17
19
18
def __iter__ (self ) -> Iterator [Any ]:
20
- """
21
- Iterate through all nodes in the Circular Linked List yielding their data.
22
- Yields:
23
- The data of each node in the linked list.
24
- """
25
19
node = self .head
26
- while node :
20
+ if node is None :
21
+ return # No nodes to iterate over
22
+ while True :
27
23
yield node .data
28
24
node = node .next_node
29
25
if node == self .head :
30
26
break
31
27
32
28
def __len__ (self ) -> int :
33
- """
34
- Get the length (number of nodes) in the Circular Linked List.
35
- """
36
29
return sum (1 for _ in self )
37
30
38
31
def __repr__ (self ) -> str :
39
- """
40
- Generate a string representation of the Circular Linked List.
41
- Returns:
42
- A string of the format "1->2->....->N".
43
- """
44
32
return "->" .join (str (item ) for item in iter (self ))
45
33
46
34
def insert_tail (self , data : Any ) -> None :
47
- """
48
- Insert a node with the given data at the end of the Circular Linked List.
49
- """
50
35
self .insert_nth (len (self ), data )
51
36
52
37
def insert_head (self , data : Any ) -> None :
53
- """
54
- Insert a node with the given data at the beginning of the Circular Linked List.
55
- """
56
38
self .insert_nth (0 , data )
57
39
58
40
def insert_nth (self , index : int , data : Any ) -> None :
59
- """
60
- Insert the data of the node at the nth pos in the Circular Linked List.
61
- Args:
62
- index: The index at which the data should be inserted.
63
- data: The data to be inserted.
64
-
65
- Raises:
66
- IndexError: If the index is out of range.
67
- """
68
41
if index < 0 or index > len (self ):
69
42
raise IndexError ("list index out of range." )
70
- new_node : Node = Node (data )
43
+ new_node = Node (data )
71
44
if self .head is None :
72
- new_node .next_node = new_node # First node points to itself
45
+ # List is empty, so new node is both head and tail, pointing to itself
46
+ new_node .next_node = new_node
73
47
self .tail = self .head = new_node
74
- elif index == 0 : # Insert at the head
48
+ elif index == 0 : # Insert at head
75
49
new_node .next_node = self .head
76
- assert self .tail is not None # List is not empty, tail exists
77
- self .head = self . tail . next_node = new_node
50
+ self .tail . next_node = new_node
51
+ self .head = new_node
78
52
else :
79
- temp : Node | None = self .head
53
+ temp = self .head
80
54
for _ in range (index - 1 ):
81
- assert temp is not None
82
55
temp = temp .next_node
83
- assert temp is not None
84
56
new_node .next_node = temp .next_node
85
57
temp .next_node = new_node
86
58
if index == len (self ) - 1 : # Insert at the tail
87
59
self .tail = new_node
88
60
89
61
def delete_front (self ) -> Any :
90
- """
91
- Delete and return the data of the node at the front of the Circular Linked List.
92
- Raises:
93
- IndexError: If the list is empty.
94
- """
95
62
return self .delete_nth (0 )
96
63
97
64
def delete_tail (self ) -> Any :
98
- """
99
- Delete and return the data of the node at the end of the Circular Linked List.
100
- Returns:
101
- Any: The data of the deleted node.
102
- Raises:
103
- IndexError: If the index is out of range.
104
- """
105
65
return self .delete_nth (len (self ) - 1 )
106
66
107
67
def delete_nth (self , index : int = 0 ) -> Any :
108
- """
109
- Delete and return the data of the node at the nth pos in Circular Linked List.
110
- Args:
111
- index (int): The index of the node to be deleted. Defaults to 0.
112
- Returns:
113
- Any: The data of the deleted node.
114
- Raises:
115
- IndexError: If the index is out of range.
116
- """
117
68
if not 0 <= index < len (self ):
118
69
raise IndexError ("list index out of range." )
70
+ if self .head is None :
71
+ raise IndexError ("Cannot delete from an empty list." )
119
72
120
- assert self .head is not None
121
- assert self .tail is not None
122
- delete_node : Node = self .head
123
- if self .head == self .tail : # Just one node
73
+ delete_node = self .head
74
+ if self .head == self .tail : # Only one node in the list
124
75
self .head = self .tail = None
125
76
elif index == 0 : # Delete head node
126
- assert self .tail .next_node is not None
127
- self .tail .next_node = self .tail .next_node .next_node
77
+ self .tail .next_node = self .head .next_node
128
78
self .head = self .head .next_node
129
79
else :
130
- temp : Node | None = self .head
80
+ temp = self .head
131
81
for _ in range (index - 1 ):
132
- assert temp is not None
133
82
temp = temp .next_node
134
- assert temp is not None
135
- assert temp .next_node is not None
136
83
delete_node = temp .next_node
137
- temp .next_node = temp . next_node .next_node
138
- if index == len ( self ) - 1 : # Delete at tail
84
+ temp .next_node = delete_node .next_node
85
+ if delete_node == self . tail : # If deleting the tail
139
86
self .tail = temp
140
87
return delete_node .data
141
88
142
89
def is_empty (self ) -> bool :
143
- """
144
- Check if the Circular Linked List is empty.
145
- Returns:
146
- bool: True if the list is empty, False otherwise.
147
- """
148
90
return len (self ) == 0
149
91
150
92
151
93
def test_circular_linked_list () -> None :
152
- """
153
- Test cases for the CircularLinkedList class.
154
- >>> test_circular_linked_list()
155
- """
156
94
circular_linked_list = CircularLinkedList ()
157
95
assert len (circular_linked_list ) == 0
158
96
assert circular_linked_list .is_empty () is True
@@ -206,5 +144,4 @@ def test_circular_linked_list() -> None:
206
144
207
145
if __name__ == "__main__" :
208
146
import doctest
209
-
210
147
doctest .testmod ()
0 commit comments