Skip to content

Commit 250ed6f

Browse files
authored
Added deque funcationality to Queue (#321)
1 parent 09b338c commit 250ed6f

File tree

2 files changed

+135
-30
lines changed

2 files changed

+135
-30
lines changed

pydatastructs/miscellaneous_data_structures/queue.py

Lines changed: 101 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ class Queue(object):
2323
dtype : A valid python type
2424
Optional, by default NoneType if item
2525
is None.
26+
Required only for 'array' implementation.
27+
double_ended : bool
28+
Optional, by default, False.
29+
Set to True if the queue should support
30+
additional, appendleft and pop operations
31+
from left and right sides respectively.
2632
2733
Examples
2834
========
@@ -47,10 +53,12 @@ def __new__(cls, implementation='array', **kwargs):
4753
if implementation == 'array':
4854
return ArrayQueue(
4955
kwargs.get('items', None),
50-
kwargs.get('dtype', int))
56+
kwargs.get('dtype', int),
57+
kwargs.get('double_ended', False))
5158
elif implementation == 'linked_list':
5259
return LinkedListQueue(
53-
kwargs.get('items', None)
60+
kwargs.get('items', None),
61+
kwargs.get('double_ended', False)
5462
)
5563
else:
5664
raise NotImplementedError(
@@ -60,10 +68,24 @@ def __new__(cls, implementation='array', **kwargs):
6068
def methods(cls):
6169
return ['__new__']
6270

71+
def _double_ended_check(self):
72+
if not self._double_ended:
73+
raise NotImplementedError(
74+
"This method is only supported for "
75+
"double ended queues.")
76+
6377
def append(self, *args, **kwargs):
6478
raise NotImplementedError(
6579
"This is an abstract method.")
6680

81+
def appendleft(self, *args, **kwargs):
82+
raise NotImplementedError(
83+
"This is an abstract method.")
84+
85+
def pop(self, *args, **kwargs):
86+
raise NotImplementedError(
87+
"This is an abstract method.")
88+
6789
def popleft(self, *args, **kwargs):
6890
raise NotImplementedError(
6991
"This is an abstract method.")
@@ -76,52 +98,94 @@ def is_empty(self):
7698

7799
class ArrayQueue(Queue):
78100

79-
__slots__ = ['front']
101+
__slots__ = ['_front', '_rear', '_double_ended']
80102

81-
def __new__(cls, items=None, dtype=NoneType):
103+
def __new__(cls, items=None, dtype=NoneType, double_ended=False):
82104
if items is None:
83105
items = DynamicOneDimensionalArray(dtype, 0)
84106
else:
85107
dtype = type(items[0])
86108
items = DynamicOneDimensionalArray(dtype, items)
87109
obj = object.__new__(cls)
88-
obj.items, obj.front = items, -1
110+
obj.items, obj._front = items, -1
89111
if items.size == 0:
90-
obj.front = -1
112+
obj._front = -1
113+
obj._rear = -1
91114
else:
92-
obj.front = 0
115+
obj._front = 0
116+
obj._rear = items._num - 1
117+
obj._double_ended = double_ended
93118
return obj
94119

95120
@classmethod
96121
def methods(cls):
97-
return ['__new__', 'append', 'popleft', 'rear',
98-
'is_empty', '__len__', '__str__']
122+
return ['__new__', 'append', 'appendleft', 'popleft',
123+
'pop', 'is_empty', '__len__', '__str__', 'front',
124+
'rear']
99125

100126
def append(self, x):
101127
if self.is_empty:
102-
self.front = 0
128+
self._front = 0
103129
self.items._dtype = type(x)
104130
self.items.append(x)
131+
self._rear += 1
132+
133+
def appendleft(self, x):
134+
self._double_ended_check()
135+
temp = []
136+
if self.is_empty:
137+
self._front = 0
138+
self._rear = -1
139+
self.items._dtype = type(x)
140+
temp.append(x)
141+
for i in range(self._front, self._rear + 1):
142+
temp.append(self.items._data[i])
143+
self.items = DynamicOneDimensionalArray(type(temp[0]), temp)
144+
self._rear += 1
105145

106146
def popleft(self):
107147
if self.is_empty:
108148
raise IndexError("Queue is empty.")
109-
return_value = dc(self.items[self.front])
110-
front_temp = self.front
111-
if self.front == self.rear:
112-
self.front = -1
149+
return_value = dc(self.items[self._front])
150+
front_temp = self._front
151+
if self._front == self._rear:
152+
self._front = -1
153+
self._rear = -1
113154
else:
114155
if (self.items._num - 1)/self.items._size < \
115156
self.items._load_factor:
116-
self.front = 0
157+
self._front = 0
117158
else:
118-
self.front += 1
159+
self._front += 1
119160
self.items.delete(front_temp)
120161
return return_value
121162

163+
def pop(self):
164+
self._double_ended_check()
165+
if self.is_empty:
166+
raise IndexError("Queue is empty.")
167+
168+
return_value = dc(self.items[self._rear])
169+
rear_temp = self._rear
170+
if self._front == self._rear:
171+
self._front = -1
172+
self._rear = -1
173+
else:
174+
if (self.items._num - 1)/self.items._size < \
175+
self.items._load_factor:
176+
self._front = 0
177+
else:
178+
self._rear -= 1
179+
self.items.delete(rear_temp)
180+
return return_value
181+
182+
@property
183+
def front(self):
184+
return self._front
185+
122186
@property
123187
def rear(self):
124-
return self.items._last_pos_filled
188+
return self._rear
125189

126190
@property
127191
def is_empty(self):
@@ -132,16 +196,15 @@ def __len__(self):
132196

133197
def __str__(self):
134198
_data = []
135-
for i in range(self.front, self.rear + 1):
199+
for i in range(self._front, self._rear + 1):
136200
_data.append(self.items._data[i])
137201
return str(_data)
138202

139-
140203
class LinkedListQueue(Queue):
141204

142-
__slots__ = ['queue']
205+
__slots__ = ['queue', '_double_ended']
143206

144-
def __new__(cls, items=None):
207+
def __new__(cls, items=None, double_ended=False):
145208
obj = object.__new__(cls)
146209
obj.queue = SinglyLinkedList()
147210
if items is None:
@@ -151,16 +214,29 @@ def __new__(cls, items=None):
151214
obj.append(x)
152215
else:
153216
raise TypeError("Expected type: list/tuple")
217+
obj._double_ended = double_ended
154218
return obj
155219

156220
@classmethod
157221
def methods(cls):
158-
return ['__new__', 'append', 'popleft', 'rear',
159-
'is_empty', '__len__', '__str__', 'front', 'size']
222+
return ['__new__', 'append', 'appendleft', 'pop', 'popleft',
223+
'is_empty', '__len__', '__str__', 'front', 'rear']
160224

161225
def append(self, x):
162226
self.queue.append(x)
163227

228+
def appendleft(self, x):
229+
self._double_ended_check()
230+
if self._double_ended:
231+
self.queue.appendleft(x)
232+
233+
def pop(self):
234+
self._double_ended_check()
235+
if self.is_empty:
236+
raise IndexError("Queue is empty.")
237+
return_value = self.queue.popright()
238+
return return_value
239+
164240
def popleft(self):
165241
if self.is_empty:
166242
raise IndexError("Queue is empty.")
@@ -169,7 +245,7 @@ def popleft(self):
169245

170246
@property
171247
def is_empty(self):
172-
return self.size == 0
248+
return self.__len__() == 0
173249

174250
@property
175251
def front(self):
@@ -179,12 +255,8 @@ def front(self):
179255
def rear(self):
180256
return self.queue.tail
181257

182-
@property
183-
def size(self):
184-
return self.queue.size
185-
186258
def __len__(self):
187-
return self.size
259+
return self.queue.size
188260

189261
def __str__(self):
190262
return str(self.queue)

pydatastructs/miscellaneous_data_structures/tests/test_queue.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ def test_ArrayQueue():
3030
assert q1.popleft() == 3
3131
assert len(q1) == 0
3232

33+
q2 = Queue(implementation='array', items=[0], double_ended=True)
34+
q2.append(1)
35+
q2.append(2)
36+
q2.appendleft(3)
37+
assert str(q2) == '[3, 0, 1, 2]'
38+
assert len(q2) == 4
39+
assert q2.popleft() == 3
40+
assert q2.pop() == 2
41+
assert len(q2) == 2
42+
assert q2.popleft() == 0
43+
assert q2.pop() == 1
44+
assert len(q2) == 0
45+
46+
q1 = Queue(implementation='array', items=[0])
47+
assert raises(NotImplementedError, lambda: q1.appendleft(2))
48+
49+
3350
def test_LinkedListQueue():
3451
q1 = Queue(implementation='linked_list')
3552
q1.append(1)
@@ -49,7 +66,6 @@ def test_LinkedListQueue():
4966

5067
q1 = Queue(implementation='linked_list',items=['a',None,type,{}])
5168
assert len(q1) == 4
52-
assert q1.size == 4
5369

5470
front = q1.front
5571
assert front.key == q1.popleft().key
@@ -60,6 +76,23 @@ def test_LinkedListQueue():
6076

6177
assert rear.key == q1.popleft().key
6278

79+
q1 = Queue(implementation='linked_list', double_ended=True)
80+
q1.appendleft(1)
81+
q2 = Queue(implementation='linked_list', items=[0, 1])
82+
assert raises(NotImplementedError, lambda: q2.appendleft(1))
83+
q1 = Queue(implementation='linked_list', items = [0, 1], double_ended=True)
84+
q1.appendleft(2)
85+
q1.append(3)
86+
assert str(q1) == "['2', '0', '1', '3']"
87+
assert len(q1) == 4
88+
assert q1.popleft().key == 2
89+
assert q1.pop().key == 3
90+
assert len(q1) == 2
91+
assert q1.pop().key == 1
92+
assert q1.popleft().key == 0
93+
assert len(q1) == 0
94+
assert raises(IndexError, lambda: q1.popleft())
95+
6396
def test_PriorityQueue():
6497
pq1 = PriorityQueue(implementation='linked_list')
6598
assert _check_type(pq1, LinkedListPriorityQueue) is True

0 commit comments

Comments
 (0)