Skip to content

Commit 0104de1

Browse files
committed
Add deque_from_scratch.py
1 parent d28463c commit 0104de1

File tree

1 file changed

+279
-0
lines changed

1 file changed

+279
-0
lines changed
Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
"""
2+
Implementation of double ended queue.
3+
"""
4+
from dataclasses import dataclass
5+
from typing import Any
6+
7+
class Deque:
8+
"""
9+
Deque data structure.
10+
11+
Operations
12+
----------
13+
append(val: Any) -> None
14+
appendleft(val: Any) -> None
15+
pop() -> Any
16+
popleft() -> Any
17+
18+
19+
Observers
20+
---------
21+
is_empty() -> bool
22+
23+
24+
Attributes
25+
----------
26+
_front: _Node
27+
front of the deque a.k.a. the first element
28+
29+
_back: _Node
30+
back of the element a.k.a. the last element
31+
32+
_len: int
33+
the number of nodes
34+
"""
35+
__slots__ = ["_front", "_back", "_len"]
36+
37+
@dataclass
38+
class _Node:
39+
"""
40+
Representation of a node.
41+
Contains a value and a pointer to the next node as well as to the previous one.
42+
"""
43+
val: Any = None
44+
next: "_Node" = None
45+
prev: "_Node" = None
46+
47+
class _Iterator:
48+
"""
49+
Helper class for iteration. Will be used to implement iteration.
50+
51+
Attributes
52+
----------
53+
_cur: _Node
54+
the current node of the iteration.
55+
"""
56+
__slots__ = ["_cur"]
57+
58+
def __init__(self, cur):
59+
self._cur = cur
60+
61+
def __iter__(self):
62+
return self
63+
64+
def __next__(self):
65+
if self._cur is None:
66+
# finished iterating
67+
raise StopIteration
68+
val = self._cur.val
69+
self._cur = self._cur.next
70+
71+
return val
72+
73+
def __init__(self, iterable = None):
74+
self._front = self._back = None
75+
self._len = 0
76+
77+
if iterable is not None:
78+
# append every value to the deque
79+
for val in iterable:
80+
self.append(val)
81+
82+
def append(self, val: Any) -> None:
83+
"""
84+
Adds val to the end of the deque.
85+
Time complexity: O(1)
86+
87+
>>> d = Deque([1, 2, 3])
88+
>>> d.append(4)
89+
>>> print(d)
90+
[1, 2, 3, 4]
91+
>>> d2 = Deque([51, "str", True])
92+
>>> d2.append([1, "2"])
93+
>>> print(d2)
94+
[51, 'str', True, [1, '2']]
95+
"""
96+
node = self._Node(val, None, None)
97+
if self.is_empty():
98+
# front = back
99+
self._front = self._back = node
100+
self._len = 1
101+
else:
102+
# connect nodes
103+
self._back.next = node
104+
node.prev = self._back
105+
self._back = node # assign new back to the new node
106+
107+
self._len += 1
108+
109+
# make sure there was no errors
110+
assert not self.is_empty(), "Error on appending value."
111+
112+
def appendleft(self, val: Any) -> None:
113+
"""
114+
Adds val to the beginning of the deque.
115+
Time complexity: O(1)
116+
117+
>>> d = Deque([2, 3])
118+
>>> d.appendleft(1)
119+
>>> print(d)
120+
[1, 2, 3]
121+
>>> d2 = Deque(["b", "c"])
122+
>>> d2.appendleft("a")
123+
>>> print(d2)
124+
['a', 'b', 'c']
125+
"""
126+
node = self._Node(val, None, None)
127+
if self.is_empty():
128+
# front = back
129+
self._front = self._back = node
130+
self._len = 1
131+
else:
132+
# connect nodes
133+
node.next = self._front
134+
self._front.prev = node
135+
self._front = node # assign new front to the new node
136+
137+
self._len += 1
138+
139+
# make sure there was no errors
140+
assert not self.is_empty(), "Error on appending value."
141+
142+
def pop(self) -> Any:
143+
"""
144+
Removes the last element of the deque and returns it.
145+
Time complexity: O(1)
146+
147+
@returns topop.val: the value of the node to pop.
148+
149+
>>> d = Deque([1, 2, 3, 15182])
150+
>>> popped = d.pop()
151+
>>> print(popped)
152+
15182
153+
>>> print(d)
154+
[1, 2, 3]
155+
"""
156+
# make sure the deque has elements to pop
157+
assert not self.is_empty(), "Deque is empty."
158+
159+
topop = self._back
160+
self._back = self._back.prev # set new back
161+
self._back.next = None # drop the last node - python will deallocate memory automatically
162+
163+
self._len -= 1
164+
165+
return topop.val
166+
167+
def popleft(self) -> Any:
168+
"""
169+
Removes the first element of the deque and returns it.
170+
Time complexity: O(1)
171+
172+
@returns topop.val: the value of the node to pop.
173+
174+
>>> d = Deque([15182, 1, 2, 3])
175+
>>> popped = d.popleft()
176+
>>> print(popped)
177+
15182
178+
>>> print(d)
179+
[1, 2, 3]
180+
"""
181+
# make sure the deque has elements to pop
182+
assert not self.is_empty(), "Deque is empty."
183+
184+
topop = self._front
185+
self._front = self._front.next # set new front and drop the first node
186+
self._front.prev = None
187+
188+
self._len -= 1
189+
190+
return topop.val
191+
192+
def is_empty(self) -> bool:
193+
"""
194+
Checks if the deque is empty.
195+
Time complexity: O(1)
196+
197+
>>> d = Deque([1, 2, 3])
198+
>>> print(d.is_empty())
199+
False
200+
>>> d2 = Deque()
201+
>>> print(d2.is_empty())
202+
True
203+
"""
204+
return self._front is None
205+
206+
def __len__(self) -> int:
207+
"""
208+
Implements len() function. Returns the length of the deque.
209+
Time complexity: O(1)
210+
211+
>>> d = Deque([1, 2, 3])
212+
>>> print(len(d))
213+
3
214+
>>> d2 = Deque()
215+
>>> print(len(d2))
216+
0
217+
"""
218+
return self._len
219+
220+
def __eq__(self, other) -> bool:
221+
"""
222+
Implements "==" operator. Returns if *self* is equal to *other*.
223+
Time complexity: O(n)
224+
225+
>>> d = Deque([1, 2, 3])
226+
>>> d2 = Deque([1, 2, 3])
227+
>>> print(d == d2)
228+
True
229+
>>> d3 = Deque([1, 2])
230+
>>> print(d == d3)
231+
False
232+
"""
233+
me = self._front
234+
oth = other._front
235+
236+
# if the length of the deques are not the same, they are not equal
237+
if len(self) != len(other):
238+
return False
239+
240+
while me is not None and oth is not None:
241+
# compare every value
242+
if me.val != oth.val:
243+
return False
244+
me = me.next
245+
oth = oth.next
246+
247+
return True
248+
249+
def __iter__(self):
250+
"""
251+
Implements iteration.
252+
Time complexity: O(1)
253+
254+
>>> d = Deque([1, 2, 3])
255+
>>> for v in d:
256+
... print(v)
257+
1
258+
2
259+
3
260+
"""
261+
return Deque._Iterator(self._front)
262+
263+
def __repr__(self) -> str:
264+
"""
265+
Implements representation of the deque.
266+
Time complexity: O(n)
267+
268+
>>> d = Deque([1, 2, 3])
269+
>>> print(d)
270+
[1, 2, 3]
271+
"""
272+
l = []
273+
aux = self._front
274+
while aux is not None:
275+
# append the values in a list to display
276+
l.append(aux.val)
277+
aux = aux.next
278+
279+
return '[' + ', '.join(repr(x) for x in l) + ']'

0 commit comments

Comments
 (0)