Skip to content

Commit

Permalink
Added deque funcationality to Queue (#321)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arvind-raj06 authored Jan 31, 2021
1 parent 09b338c commit 250ed6f
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 30 deletions.
130 changes: 101 additions & 29 deletions pydatastructs/miscellaneous_data_structures/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ class Queue(object):
dtype : A valid python type
Optional, by default NoneType if item
is None.
Required only for 'array' implementation.
double_ended : bool
Optional, by default, False.
Set to True if the queue should support
additional, appendleft and pop operations
from left and right sides respectively.
Examples
========
Expand All @@ -47,10 +53,12 @@ def __new__(cls, implementation='array', **kwargs):
if implementation == 'array':
return ArrayQueue(
kwargs.get('items', None),
kwargs.get('dtype', int))
kwargs.get('dtype', int),
kwargs.get('double_ended', False))
elif implementation == 'linked_list':
return LinkedListQueue(
kwargs.get('items', None)
kwargs.get('items', None),
kwargs.get('double_ended', False)
)
else:
raise NotImplementedError(
Expand All @@ -60,10 +68,24 @@ def __new__(cls, implementation='array', **kwargs):
def methods(cls):
return ['__new__']

def _double_ended_check(self):
if not self._double_ended:
raise NotImplementedError(
"This method is only supported for "
"double ended queues.")

def append(self, *args, **kwargs):
raise NotImplementedError(
"This is an abstract method.")

def appendleft(self, *args, **kwargs):
raise NotImplementedError(
"This is an abstract method.")

def pop(self, *args, **kwargs):
raise NotImplementedError(
"This is an abstract method.")

def popleft(self, *args, **kwargs):
raise NotImplementedError(
"This is an abstract method.")
Expand All @@ -76,52 +98,94 @@ def is_empty(self):

class ArrayQueue(Queue):

__slots__ = ['front']
__slots__ = ['_front', '_rear', '_double_ended']

def __new__(cls, items=None, dtype=NoneType):
def __new__(cls, items=None, dtype=NoneType, double_ended=False):
if items is None:
items = DynamicOneDimensionalArray(dtype, 0)
else:
dtype = type(items[0])
items = DynamicOneDimensionalArray(dtype, items)
obj = object.__new__(cls)
obj.items, obj.front = items, -1
obj.items, obj._front = items, -1
if items.size == 0:
obj.front = -1
obj._front = -1
obj._rear = -1
else:
obj.front = 0
obj._front = 0
obj._rear = items._num - 1
obj._double_ended = double_ended
return obj

@classmethod
def methods(cls):
return ['__new__', 'append', 'popleft', 'rear',
'is_empty', '__len__', '__str__']
return ['__new__', 'append', 'appendleft', 'popleft',
'pop', 'is_empty', '__len__', '__str__', 'front',
'rear']

def append(self, x):
if self.is_empty:
self.front = 0
self._front = 0
self.items._dtype = type(x)
self.items.append(x)
self._rear += 1

def appendleft(self, x):
self._double_ended_check()
temp = []
if self.is_empty:
self._front = 0
self._rear = -1
self.items._dtype = type(x)
temp.append(x)
for i in range(self._front, self._rear + 1):
temp.append(self.items._data[i])
self.items = DynamicOneDimensionalArray(type(temp[0]), temp)
self._rear += 1

def popleft(self):
if self.is_empty:
raise IndexError("Queue is empty.")
return_value = dc(self.items[self.front])
front_temp = self.front
if self.front == self.rear:
self.front = -1
return_value = dc(self.items[self._front])
front_temp = self._front
if self._front == self._rear:
self._front = -1
self._rear = -1
else:
if (self.items._num - 1)/self.items._size < \
self.items._load_factor:
self.front = 0
self._front = 0
else:
self.front += 1
self._front += 1
self.items.delete(front_temp)
return return_value

def pop(self):
self._double_ended_check()
if self.is_empty:
raise IndexError("Queue is empty.")

return_value = dc(self.items[self._rear])
rear_temp = self._rear
if self._front == self._rear:
self._front = -1
self._rear = -1
else:
if (self.items._num - 1)/self.items._size < \
self.items._load_factor:
self._front = 0
else:
self._rear -= 1
self.items.delete(rear_temp)
return return_value

@property
def front(self):
return self._front

@property
def rear(self):
return self.items._last_pos_filled
return self._rear

@property
def is_empty(self):
Expand All @@ -132,16 +196,15 @@ def __len__(self):

def __str__(self):
_data = []
for i in range(self.front, self.rear + 1):
for i in range(self._front, self._rear + 1):
_data.append(self.items._data[i])
return str(_data)


class LinkedListQueue(Queue):

__slots__ = ['queue']
__slots__ = ['queue', '_double_ended']

def __new__(cls, items=None):
def __new__(cls, items=None, double_ended=False):
obj = object.__new__(cls)
obj.queue = SinglyLinkedList()
if items is None:
Expand All @@ -151,16 +214,29 @@ def __new__(cls, items=None):
obj.append(x)
else:
raise TypeError("Expected type: list/tuple")
obj._double_ended = double_ended
return obj

@classmethod
def methods(cls):
return ['__new__', 'append', 'popleft', 'rear',
'is_empty', '__len__', '__str__', 'front', 'size']
return ['__new__', 'append', 'appendleft', 'pop', 'popleft',
'is_empty', '__len__', '__str__', 'front', 'rear']

def append(self, x):
self.queue.append(x)

def appendleft(self, x):
self._double_ended_check()
if self._double_ended:
self.queue.appendleft(x)

def pop(self):
self._double_ended_check()
if self.is_empty:
raise IndexError("Queue is empty.")
return_value = self.queue.popright()
return return_value

def popleft(self):
if self.is_empty:
raise IndexError("Queue is empty.")
Expand All @@ -169,7 +245,7 @@ def popleft(self):

@property
def is_empty(self):
return self.size == 0
return self.__len__() == 0

@property
def front(self):
Expand All @@ -179,12 +255,8 @@ def front(self):
def rear(self):
return self.queue.tail

@property
def size(self):
return self.queue.size

def __len__(self):
return self.size
return self.queue.size

def __str__(self):
return str(self.queue)
Expand Down
35 changes: 34 additions & 1 deletion pydatastructs/miscellaneous_data_structures/tests/test_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ def test_ArrayQueue():
assert q1.popleft() == 3
assert len(q1) == 0

q2 = Queue(implementation='array', items=[0], double_ended=True)
q2.append(1)
q2.append(2)
q2.appendleft(3)
assert str(q2) == '[3, 0, 1, 2]'
assert len(q2) == 4
assert q2.popleft() == 3
assert q2.pop() == 2
assert len(q2) == 2
assert q2.popleft() == 0
assert q2.pop() == 1
assert len(q2) == 0

q1 = Queue(implementation='array', items=[0])
assert raises(NotImplementedError, lambda: q1.appendleft(2))


def test_LinkedListQueue():
q1 = Queue(implementation='linked_list')
q1.append(1)
Expand All @@ -49,7 +66,6 @@ def test_LinkedListQueue():

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

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

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

q1 = Queue(implementation='linked_list', double_ended=True)
q1.appendleft(1)
q2 = Queue(implementation='linked_list', items=[0, 1])
assert raises(NotImplementedError, lambda: q2.appendleft(1))
q1 = Queue(implementation='linked_list', items = [0, 1], double_ended=True)
q1.appendleft(2)
q1.append(3)
assert str(q1) == "['2', '0', '1', '3']"
assert len(q1) == 4
assert q1.popleft().key == 2
assert q1.pop().key == 3
assert len(q1) == 2
assert q1.pop().key == 1
assert q1.popleft().key == 0
assert len(q1) == 0
assert raises(IndexError, lambda: q1.popleft())

def test_PriorityQueue():
pq1 = PriorityQueue(implementation='linked_list')
assert _check_type(pq1, LinkedListPriorityQueue) is True
Expand Down

0 comments on commit 250ed6f

Please sign in to comment.