Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Deque - Array #321

Merged
merged 9 commits into from
Jan 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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