1
+ from typing import Any
2
+
3
+
1
4
class Node :
2
- def __init__ (self , data ):
5
+ def __init__ (self , data : Any ):
6
+ """
7
+ Create and initialize Node class instance.
8
+ >>> Node(20)
9
+ Node(20)
10
+ >>> Node("Hello, world!")
11
+ Node(Hello, world!)
12
+ >>> Node(None)
13
+ Node(None)
14
+ >>> Node(True)
15
+ Node(True)
16
+ """
3
17
self .data = data
4
18
self .next = None
5
19
6
- def __repr__ (self ):
20
+ def __repr__ (self ) -> str :
21
+ """
22
+ Get the string representation of this node.
23
+ >>> Node(10).__repr__()
24
+ 'Node(10)'
25
+ """
7
26
return f"Node({ self .data } )"
8
27
9
28
10
29
class LinkedList :
11
30
def __init__ (self ):
31
+ """
32
+ Create and initialize LinkedList class instance.
33
+ >>> linked_list = LinkedList()
34
+ """
12
35
self .head = None
13
36
14
- def __iter__ (self ):
37
+ def __iter__ (self ) -> Any :
38
+ """
39
+ This function is intended for iterators to access
40
+ and iterate through data inside linked list.
41
+ >>> linked_list = LinkedList()
42
+ >>> linked_list.insert_tail("tail")
43
+ >>> linked_list.insert_tail("tail_1")
44
+ >>> linked_list.insert_tail("tail_2")
45
+ >>> for node in linked_list: # __iter__ used here.
46
+ ... node
47
+ 'tail'
48
+ 'tail_1'
49
+ 'tail_2'
50
+ """
15
51
node = self .head
16
52
while node :
17
53
yield node .data
@@ -23,7 +59,7 @@ def __len__(self) -> int:
23
59
>>> linked_list = LinkedList()
24
60
>>> len(linked_list)
25
61
0
26
- >>> linked_list.insert_tail("head ")
62
+ >>> linked_list.insert_tail("tail ")
27
63
>>> len(linked_list)
28
64
1
29
65
>>> linked_list.insert_head("head")
@@ -38,13 +74,18 @@ def __len__(self) -> int:
38
74
"""
39
75
return len (tuple (iter (self )))
40
76
41
- def __repr__ (self ):
77
+ def __repr__ (self ) -> str :
42
78
"""
43
79
String representation/visualization of a Linked Lists
80
+ >>> linked_list = LinkedList()
81
+ >>> linked_list.insert_tail(1)
82
+ >>> linked_list.insert_tail(3)
83
+ >>> linked_list.__repr__()
84
+ '1->3'
44
85
"""
45
86
return "->" .join ([str (item ) for item in self ])
46
87
47
- def __getitem__ (self , index ) :
88
+ def __getitem__ (self , index : int ) -> Any :
48
89
"""
49
90
Indexing Support. Used to get a node at particular position
50
91
>>> linked_list = LinkedList()
@@ -68,7 +109,7 @@ def __getitem__(self, index):
68
109
return node
69
110
70
111
# Used to change the data of a particular node
71
- def __setitem__ (self , index , data ) :
112
+ def __setitem__ (self , index : int , data : Any ) -> None :
72
113
"""
73
114
>>> linked_list = LinkedList()
74
115
>>> for i in range(0, 10):
@@ -95,13 +136,54 @@ def __setitem__(self, index, data):
95
136
current = current .next
96
137
current .data = data
97
138
98
- def insert_tail (self , data ) -> None :
139
+ def insert_tail (self , data : Any ) -> None :
140
+ """
141
+ Insert data to the tail end of linked list.
142
+ >>> linked_list = LinkedList()
143
+ >>> linked_list.insert_tail("tail")
144
+ >>> linked_list
145
+ tail
146
+ >>> linked_list.insert_tail("tail_2")
147
+ >>> linked_list
148
+ tail->tail_2
149
+ >>> linked_list.insert_tail("tail_3")
150
+ >>> linked_list
151
+ tail->tail_2->tail_3
152
+ """
99
153
self .insert_nth (len (self ), data )
100
154
101
- def insert_head (self , data ) -> None :
155
+ def insert_head (self , data : Any ) -> None :
156
+ """
157
+ Insert data to the head first of linked list.
158
+ >>> linked_list = LinkedList()
159
+ >>> linked_list.insert_head("head")
160
+ >>> linked_list
161
+ head
162
+ >>> linked_list.insert_head("head_2")
163
+ >>> linked_list
164
+ head_2->head
165
+ >>> linked_list.insert_head("head_3")
166
+ >>> linked_list
167
+ head_3->head_2->head
168
+ """
102
169
self .insert_nth (0 , data )
103
170
104
- def insert_nth (self , index : int , data ) -> None :
171
+ def insert_nth (self , index : int , data : Any ) -> None :
172
+ """
173
+ Insert data at given index.
174
+ >>> linked_list = LinkedList()
175
+ >>> linked_list.insert_tail("first")
176
+ >>> linked_list.insert_tail("second")
177
+ >>> linked_list.insert_tail("third")
178
+ >>> linked_list
179
+ first->second->third
180
+ >>> linked_list.insert_nth(1, "fourth")
181
+ >>> linked_list
182
+ first->fourth->second->third
183
+ >>> linked_list.insert_nth(3, "fifth")
184
+ >>> linked_list
185
+ first->fourth->second->fifth->third
186
+ """
105
187
if not 0 <= index <= len (self ):
106
188
raise IndexError ("list index out of range" )
107
189
new_node = Node (data )
@@ -118,17 +200,84 @@ def insert_nth(self, index: int, data) -> None:
118
200
temp .next = new_node
119
201
120
202
def print_list (self ) -> None : # print every node data
203
+ """
204
+ This method prints every node data.
205
+ >>> linked_list = LinkedList()
206
+ >>> linked_list.insert_tail("first")
207
+ >>> linked_list.insert_tail("second")
208
+ >>> linked_list.insert_tail("third")
209
+ >>> linked_list
210
+ first->second->third
211
+ """
121
212
print (self )
122
213
123
- def delete_head (self ):
214
+ def delete_head (self ) -> Any :
215
+ """
216
+ Delete the head first node and return the deleted
217
+ node's data.
218
+ >>> linked_list = LinkedList()
219
+ >>> linked_list.insert_tail("first")
220
+ >>> linked_list.insert_tail("second")
221
+ >>> linked_list.insert_tail("third")
222
+ >>> linked_list
223
+ first->second->third
224
+ >>> linked_list.delete_head()
225
+ 'first'
226
+ >>> linked_list
227
+ second->third
228
+ >>> linked_list.delete_head()
229
+ 'second'
230
+ >>> linked_list
231
+ third
232
+ """
124
233
return self .delete_nth (0 )
125
234
126
- def delete_tail (self ): # delete from tail
235
+ def delete_tail (self ) -> Any : # delete from tail
236
+ """
237
+ Delete the tail end node and return the deleted
238
+ node's data.
239
+ >>> linked_list = LinkedList()
240
+ >>> linked_list.insert_tail("first")
241
+ >>> linked_list.insert_tail("second")
242
+ >>> linked_list.insert_tail("third")
243
+ >>> linked_list
244
+ first->second->third
245
+ >>> linked_list.delete_tail()
246
+ 'third'
247
+ >>> linked_list
248
+ first->second
249
+ >>> linked_list.delete_tail()
250
+ 'second'
251
+ >>> linked_list
252
+ first
253
+ """
127
254
return self .delete_nth (len (self ) - 1 )
128
255
129
- def delete_nth (self , index : int = 0 ):
256
+ def delete_nth (self , index : int = 0 ) -> Any :
257
+ """
258
+ Delete node at given index and return the deleted
259
+ node's data.
260
+ >>> linked_list = LinkedList()
261
+ >>> linked_list.insert_tail("first")
262
+ >>> linked_list.insert_tail("second")
263
+ >>> linked_list.insert_tail("third")
264
+ >>> linked_list
265
+ first->second->third
266
+ >>> linked_list.delete_nth(1) # delete middle
267
+ 'second'
268
+ >>> linked_list
269
+ first->third
270
+ >>> linked_list.delete_nth(5) # this raises error
271
+ Traceback (most recent call last):
272
+ ...
273
+ IndexError: List index out of range.
274
+ >>> linked_list.delete_nth(-1) # this also raises error
275
+ Traceback (most recent call last):
276
+ ...
277
+ IndexError: List index out of range.
278
+ """
130
279
if not 0 <= index <= len (self ) - 1 : # test if index is valid
131
- raise IndexError ("list index out of range" )
280
+ raise IndexError ("List index out of range. " )
132
281
delete_node = self .head # default first node
133
282
if index == 0 :
134
283
self .head = self .head .next
@@ -141,9 +290,30 @@ def delete_nth(self, index: int = 0):
141
290
return delete_node .data
142
291
143
292
def is_empty (self ) -> bool :
293
+ """
294
+ Check if linked list is empty.
295
+ >>> linked_list = LinkedList()
296
+ >>> linked_list.is_empty()
297
+ True
298
+ >>> linked_list.insert_head("first")
299
+ >>> linked_list.is_empty()
300
+ False
301
+ """
144
302
return self .head is None
145
303
146
- def reverse (self ):
304
+ def reverse (self ) -> None :
305
+ """
306
+ This reverses the linked list order.
307
+ >>> linked_list = LinkedList()
308
+ >>> linked_list.insert_tail("first")
309
+ >>> linked_list.insert_tail("second")
310
+ >>> linked_list.insert_tail("third")
311
+ >>> linked_list
312
+ first->second->third
313
+ >>> linked_list.reverse()
314
+ >>> linked_list
315
+ third->second->first
316
+ """
147
317
prev = None
148
318
current = self .head
149
319
@@ -201,6 +371,89 @@ def test_singly_linked_list() -> None:
201
371
linked_list [i ] = - i
202
372
assert all (linked_list [i ] == - i for i in range (0 , 9 )) is True
203
373
374
+ linked_list .reverse ()
375
+ assert str (linked_list ) == "->" .join (str (i ) for i in range (- 8 , 1 ))
376
+
377
+
378
+ def test_singly_linked_list_2 () -> None :
379
+ """
380
+ This section of the test checks for certain conditions.
381
+ >>> test_singly_linked_list_2()
382
+ """
383
+ input = [
384
+ - 9 ,
385
+ 100 ,
386
+ Node (77345112 ),
387
+ "dlrow olleH" ,
388
+ 7 ,
389
+ 5555 ,
390
+ 0 ,
391
+ - 192.55555 ,
392
+ "Hello, world!" ,
393
+ 77.9 ,
394
+ Node (10 ),
395
+ None ,
396
+ None ,
397
+ 12.20 ,
398
+ ]
399
+ linked_list = LinkedList ()
400
+ [linked_list .insert_tail (i ) for i in input ]
401
+
402
+ # Check if it's empty or not
403
+ assert linked_list .is_empty () is False
404
+ assert (
405
+ str (linked_list ) == "-9->100->Node(77345112)->dlrow olleH->7->5555->0->"
406
+ "-192.55555->Hello, world!->77.9->Node(10)->None->None->12.2"
407
+ )
408
+
409
+ # Delete the head
410
+ result = linked_list .delete_head ()
411
+ assert result == - 9
412
+ assert (
413
+ str (linked_list ) == "100->Node(77345112)->dlrow olleH->7->5555->0->-192.55555->"
414
+ "Hello, world!->77.9->Node(10)->None->None->12.2"
415
+ )
416
+
417
+ # Delete the tail
418
+ result = linked_list .delete_tail ()
419
+ assert result == 12.2
420
+ assert (
421
+ str (linked_list ) == "100->Node(77345112)->dlrow olleH->7->5555->0->-192.55555->"
422
+ "Hello, world!->77.9->Node(10)->None->None"
423
+ )
424
+
425
+ # Delete a node in specific location in linked list
426
+ result = linked_list .delete_nth (10 )
427
+ assert result is None
428
+ assert (
429
+ str (linked_list ) == "100->Node(77345112)->dlrow olleH->7->5555->0->-192.55555->"
430
+ "Hello, world!->77.9->Node(10)->None"
431
+ )
432
+
433
+ # Add a Node instance to its head
434
+ linked_list .insert_head (Node ("Hello again, world!" ))
435
+ assert (
436
+ str (linked_list )
437
+ == "Node(Hello again, world!)->100->Node(77345112)->dlrow olleH->"
438
+ "7->5555->0->-192.55555->Hello, world!->77.9->Node(10)->None"
439
+ )
440
+
441
+ # Add None to its tail
442
+ linked_list .insert_tail (None )
443
+ assert (
444
+ str (linked_list )
445
+ == "Node(Hello again, world!)->100->Node(77345112)->dlrow olleH->"
446
+ "7->5555->0->-192.55555->Hello, world!->77.9->Node(10)->None->None"
447
+ )
448
+
449
+ # Reverse the linked list
450
+ linked_list .reverse ()
451
+ assert (
452
+ str (linked_list )
453
+ == "None->None->Node(10)->77.9->Hello, world!->-192.55555->0->5555->"
454
+ "7->dlrow olleH->Node(77345112)->100->Node(Hello again, world!)"
455
+ )
456
+
204
457
205
458
def main ():
206
459
from doctest import testmod
0 commit comments