-
Notifications
You must be signed in to change notification settings - Fork 65
/
doubly_linked_list.py
187 lines (152 loc) · 5.16 KB
/
doubly_linked_list.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
""" Implementation of Doubly linked list Data Structure """
class Node:
""" Node class contains everything related to linked list node """
def __init__(self, data):
""" initializing single node with data """
self.data = data
self.next = None
self.previous = None
class DoublyLinkedList:
""" A Doubly linked list (DLL) contains an extra pointer, typically
called previous pointer, together with next pointer and data which
are there in singly linked list.
"""
def __init__(self):
""" initializing doublt linked list with zero node """
self.head = None
def is_empty(self):
""" returns True if the linked list is empty. Otherwise, return False.
"""
return self.head is None
def __len__(self):
""" Traverses the linked list and returns an integer value representing
the number of nodes in the linked list.
The time complexity is O(n) because every node in the linked list
must be visited in order to calculate the size of the linked list.
"""
if self.head is None:
return 0
count = 0
current = self.head
# While there are still Nodes left to count
while current is not None:
count += 1
current = current.next
return count
def insert_head(self, data):
""" inserts node at the start of doubly linked list """
if self.head is None:
self.head = Node(data)
return
new_node = Node(data)
current = self.head
new_node.next = current
current.previous = new_node
self.head = new_node
def insert_tail(self, data):
""" inserts node at the end of doubly linked list """
if self.head is None:
self.head = Node(data)
return
current = self.head
new_node = Node(data)
while current.next is not None:
current = current.next
current.next = new_node
new_node.previous = current
def insert_at(self, position, data):
""" inserts node at particular position in doubly linked list.
index starts from 0.
"""
dll_size = len(self)
if position < 0 or position > dll_size:
raise Exception("Invalid position")
if position == dll_size:
self.insert_tail(data)
return
if position == 0:
self.insert_head(data)
return
current = self.head
for _ in range(0, position):
current = current.next
new_node = Node(data)
previous = current.previous
previous.next = new_node
current.previous = new_node
new_node.next = current
new_node.previous = previous
def delete_head(self):
""" removes first node and returns data. Raise exception,
if doubly linked list is empty
"""
if self.head is None:
raise Exception("linked list is already empty")
if self.head.next is None:
self.head = None
return
self.head = self.head.next
self.head.previous = None
def delete_tail(self):
""" removes last node and returns data. raise exception,
if doubly linked list is empty
"""
if self.head is None:
raise Exception("linked list is already empty")
if self.head.next is None:
self.head = None
return
current = self.head
while current.next is not None:
current = current.next
previous = current.previous
current.previous = None
previous.next = None
del current
def delete_at(self, position):
""" removes specified node from doubly linked list and returns data.
raise exception, if position is invalid.
"""
dll_size = len(self)
if position < 0 or position > dll_size:
raise Exception("Invalid position")
if position == 0:
self.delete_head()
elif position == dll_size:
self.delete_tail()
else:
current = self.head
for _ in range(0, position):
current = current.next
previous_node = current.previous
next_node = current.next
previous_node.next = next_node
next_node.previous = previous_node
del current
def print(self):
""" prints entire linked list without changing underlying data """
current = self.head
while current is not None:
print(" <->", current.data, end="")
current = current.next
print()
def main():
""" operational function """
dll = DoublyLinkedList()
print("is_empty?", dll.is_empty())
dll.insert_head(3)
print("is_empty?", dll.is_empty())
dll.insert_head(2)
dll.insert_head(1)
dll.insert_tail(4)
dll.insert_tail(5)
dll.insert_tail(6)
print("size?", len(dll))
dll.print()
dll.insert_at(3, 66)
dll.print()
print("deleting head")
dll.delete_at(3)
dll.print()
if __name__ == '__main__':
main()