Skip to content

Commit 2dc311a

Browse files
realDuYuanChaogithub-actionscclauss
authored andcommitted
Updated singly_linked_list (TheAlgorithms#2477)
* Updated singly_linked_list * fixup! Format Python code with psf/black push * undo __repr__ * updating DIRECTORY.md * UNTESTED CHANGES: Add an .__iter__() method. This will break tests, etc. * fixup! Format Python code with psf/black push * len(tuple(iter(self))) * fixed __repr__() * Update data_structures/linked_list/singly_linked_list.py Co-authored-by: Christian Clauss <[email protected]> * Update data_structures/linked_list/singly_linked_list.py Co-authored-by: Christian Clauss <[email protected]> * Update data_structures/linked_list/singly_linked_list.py Co-authored-by: Christian Clauss <[email protected]> * Update data_structures/linked_list/singly_linked_list.py Co-authored-by: Christian Clauss <[email protected]> * Update data_structures/linked_list/singly_linked_list.py Co-authored-by: Christian Clauss <[email protected]> * Update data_structures/linked_list/singly_linked_list.py Co-authored-by: Christian Clauss <[email protected]> * Update data_structures/linked_list/singly_linked_list.py Co-authored-by: Christian Clauss <[email protected]> Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Christian Clauss <[email protected]>
1 parent b79b01b commit 2dc311a

File tree

2 files changed

+143
-108
lines changed

2 files changed

+143
-108
lines changed

DIRECTORY.md

+2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
* [Sum Of Subsets](https://github.com/TheAlgorithms/Python/blob/master/backtracking/sum_of_subsets.py)
2626

2727
## Bit Manipulation
28+
* [Binary And Operator](https://github.com/TheAlgorithms/Python/blob/master/bit_manipulation/binary_and_operator.py)
2829
* [Binary Or Operator](https://github.com/TheAlgorithms/Python/blob/master/bit_manipulation/binary_or_operator.py)
30+
* [Binary Xor Operator](https://github.com/TheAlgorithms/Python/blob/master/bit_manipulation/binary_xor_operator.py)
2931

3032
## Blockchain
3133
* [Chinese Remainder Theorem](https://github.com/TheAlgorithms/Python/blob/master/blockchain/chinese_remainder_theorem.py)

data_structures/linked_list/singly_linked_list.py

+141-108
Original file line numberDiff line numberDiff line change
@@ -9,50 +9,110 @@ def __repr__(self):
99

1010
class LinkedList:
1111
def __init__(self):
12-
self.head = None # initialize head to None
12+
self.head = None
13+
14+
def __iter__(self):
15+
node = self.head
16+
while node:
17+
yield node.data
18+
node = node.next
19+
20+
def __len__(self) -> int:
21+
"""
22+
Return length of linked list i.e. number of nodes
23+
>>> linked_list = LinkedList()
24+
>>> len(linked_list)
25+
0
26+
>>> linked_list.insert_tail("head")
27+
>>> len(linked_list)
28+
1
29+
>>> linked_list.insert_head("head")
30+
>>> len(linked_list)
31+
2
32+
>>> _ = linked_list.delete_tail()
33+
>>> len(linked_list)
34+
1
35+
>>> _ = linked_list.delete_head()
36+
>>> len(linked_list)
37+
0
38+
"""
39+
return len(tuple(iter(self)))
40+
41+
def __repr__(self):
42+
"""
43+
String representation/visualization of a Linked Lists
44+
"""
45+
return "->".join([str(item) for item in self])
46+
47+
def __getitem__(self, index):
48+
"""
49+
Indexing Support. Used to get a node at particular position
50+
"""
51+
if index < 0:
52+
raise ValueError("Negative indexes are not yet supported")
53+
for i, node in enumerate(self):
54+
if i == index:
55+
return node.data
56+
57+
# Used to change the data of a particular node
58+
def __setitem__(self, index, data):
59+
current = self.head
60+
# If list is empty
61+
if current is None:
62+
raise IndexError("The Linked List is empty")
63+
for i in range(index):
64+
if current.next is None:
65+
raise IndexError("list index out of range")
66+
current = current.next
67+
current.data = data
1368

1469
def insert_tail(self, data) -> None:
70+
self.insert_nth(len(self), data)
71+
72+
def insert_head(self, data) -> None:
73+
self.insert_nth(0, data)
74+
75+
def insert_nth(self, index: int, data) -> None:
76+
if not 0 <= index <= len(self):
77+
raise IndexError("list index out of range")
78+
new_node = Node(data)
1579
if self.head is None:
16-
self.insert_head(data) # if this is first node, call insert_head
80+
self.head = new_node
81+
elif index == 0:
82+
new_node.next = self.head # link new_node to head
83+
self.head = new_node
1784
else:
1885
temp = self.head
19-
while temp.next: # traverse to last node
86+
for _ in range(index - 1):
2087
temp = temp.next
21-
temp.next = Node(data) # create node & link to tail
22-
23-
def insert_head(self, data) -> None:
24-
new_node = Node(data) # create a new node
25-
if self.head:
26-
new_node.next = self.head # link new_node to head
27-
self.head = new_node # make NewNode as head
88+
new_node.next = temp.next
89+
temp.next = new_node
2890

2991
def print_list(self) -> None: # print every node data
30-
temp = self.head
31-
while temp:
32-
print(temp.data)
33-
temp = temp.next
34-
35-
def delete_head(self): # delete from head
36-
temp = self.head
37-
if self.head:
38-
self.head = self.head.next
39-
temp.next = None
40-
return temp
92+
print(self)
93+
94+
def delete_head(self):
95+
return self.delete_nth(0)
4196

4297
def delete_tail(self): # delete from tail
43-
temp = self.head
44-
if self.head:
45-
if self.head.next is None: # if head is the only Node in the Linked List
46-
self.head = None
47-
else:
48-
while temp.next.next: # find the 2nd last element
49-
temp = temp.next
50-
# (2nd last element).next = None and temp = last element
51-
temp.next, temp = None, temp.next
52-
return temp
98+
return self.delete_nth(len(self) - 1)
99+
100+
def delete_nth(self, index: int = 0):
101+
if not 0 <= index <= len(self) - 1: # test if index is valid
102+
raise IndexError("list index out of range")
103+
delete_node = self.head # default first node
104+
if index == 0:
105+
self.head = self.head.next
106+
else:
107+
temp = self.head
108+
for _ in range(index - 1):
109+
temp = temp.next
110+
delete_node = temp.next
111+
temp.next = temp.next.next
112+
return delete_node.data
53113

54114
def is_empty(self) -> bool:
55-
return self.head is None # return True if head is none
115+
return self.head is None
56116

57117
def reverse(self):
58118
prev = None
@@ -70,101 +130,74 @@ def reverse(self):
70130
# Return prev in order to put the head at the end
71131
self.head = prev
72132

73-
def __repr__(self): # String representation/visualization of a Linked Lists
74-
current = self.head
75-
string_repr = ""
76-
while current:
77-
string_repr += f"{current} --> "
78-
current = current.next
79-
# END represents end of the LinkedList
80-
return string_repr + "END"
81133

82-
# Indexing Support. Used to get a node at particular position
83-
def __getitem__(self, index):
84-
current = self.head
134+
def test_singly_linked_list() -> None:
135+
"""
136+
>>> test_singly_linked_list()
137+
"""
138+
linked_list = LinkedList()
139+
assert linked_list.is_empty() is True
140+
assert str(linked_list) == ""
85141

86-
# If LinkedList is empty
87-
if current is None:
88-
raise IndexError("The Linked List is empty")
142+
try:
143+
linked_list.delete_head()
144+
assert False # This should not happen.
145+
except IndexError:
146+
assert True # This should happen.
89147

90-
# Move Forward 'index' times
91-
for _ in range(index):
92-
# If the LinkedList ends before reaching specified node
93-
if current.next is None:
94-
raise IndexError("Index out of range.")
95-
current = current.next
96-
return current
148+
try:
149+
linked_list.delete_tail()
150+
assert False # This should not happen.
151+
except IndexError:
152+
assert True # This should happen.
97153

98-
# Used to change the data of a particular node
99-
def __setitem__(self, index, data):
100-
current = self.head
101-
# If list is empty
102-
if current is None:
103-
raise IndexError("The Linked List is empty")
104-
for i in range(index):
105-
if current.next is None:
106-
raise IndexError("Index out of range.")
107-
current = current.next
108-
current.data = data
154+
for i in range(10):
155+
assert len(linked_list) == i
156+
linked_list.insert_nth(i, i + 1)
157+
assert str(linked_list) == "->".join(str(i) for i in range(1, 11))
109158

110-
def __len__(self):
111-
"""
112-
Return length of linked list i.e. number of nodes
113-
>>> linked_list = LinkedList()
114-
>>> len(linked_list)
115-
0
116-
>>> linked_list.insert_tail("head")
117-
>>> len(linked_list)
118-
1
119-
>>> linked_list.insert_head("head")
120-
>>> len(linked_list)
121-
2
122-
>>> _ = linked_list.delete_tail()
123-
>>> len(linked_list)
124-
1
125-
>>> _ = linked_list.delete_head()
126-
>>> len(linked_list)
127-
0
128-
"""
129-
if not self.head:
130-
return 0
159+
linked_list.insert_head(0)
160+
linked_list.insert_tail(11)
161+
assert str(linked_list) == "->".join(str(i) for i in range(0, 12))
131162

132-
count = 0
133-
cur_node = self.head
134-
while cur_node.next:
135-
count += 1
136-
cur_node = cur_node.next
137-
return count + 1
163+
assert linked_list.delete_head() == 0
164+
assert linked_list.delete_nth(9) == 10
165+
assert linked_list.delete_tail() == 11
166+
assert str(linked_list) == "->".join(str(i) for i in range(1, 10))
138167

139168

140169
def main():
141-
A = LinkedList()
142-
A.insert_head(input("Inserting 1st at head ").strip())
143-
A.insert_head(input("Inserting 2nd at head ").strip())
170+
from doctest import testmod
171+
172+
testmod()
173+
174+
linked_list = LinkedList()
175+
linked_list.insert_head(input("Inserting 1st at head ").strip())
176+
linked_list.insert_head(input("Inserting 2nd at head ").strip())
144177
print("\nPrint list:")
145-
A.print_list()
146-
A.insert_tail(input("\nInserting 1st at tail ").strip())
147-
A.insert_tail(input("Inserting 2nd at tail ").strip())
178+
linked_list.print_list()
179+
linked_list.insert_tail(input("\nInserting 1st at tail ").strip())
180+
linked_list.insert_tail(input("Inserting 2nd at tail ").strip())
148181
print("\nPrint list:")
149-
A.print_list()
182+
linked_list.print_list()
150183
print("\nDelete head")
151-
A.delete_head()
184+
linked_list.delete_head()
152185
print("Delete tail")
153-
A.delete_tail()
186+
linked_list.delete_tail()
154187
print("\nPrint list:")
155-
A.print_list()
188+
linked_list.print_list()
156189
print("\nReverse linked list")
157-
A.reverse()
190+
linked_list.reverse()
158191
print("\nPrint list:")
159-
A.print_list()
192+
linked_list.print_list()
160193
print("\nString representation of linked list:")
161-
print(A)
194+
print(linked_list)
162195
print("\nReading/changing Node data using indexing:")
163-
print(f"Element at Position 1: {A[1]}")
164-
A[1] = input("Enter New Value: ").strip()
196+
print(f"Element at Position 1: {linked_list[1]}")
197+
linked_list[1] = input("Enter New Value: ").strip()
165198
print("New list:")
166-
print(A)
167-
print(f"length of A is : {len(A)}")
199+
print(linked_list)
200+
print(f"length of linked_list is : {len(linked_list)}")
168201

169202

170203
if __name__ == "__main__":

0 commit comments

Comments
 (0)