Skip to content

Commit

Permalink
Added more implementations of priority queue (#205)
Browse files Browse the repository at this point in the history
Minor changes have been made to interface of BinomialHeap and DHeap along with adding more implementations.
  • Loading branch information
czgdp1807 authored Mar 24, 2020
1 parent 2c938b5 commit a5a7ad9
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 27 deletions.
93 changes: 81 additions & 12 deletions pydatastructs/miscellaneous_data_structures/queue.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pydatastructs.linear_data_structures import DynamicOneDimensionalArray, SinglyLinkedList
from pydatastructs.utils.misc_util import NoneType, LinkedListNode, _check_type
from pydatastructs.trees.heaps import BinaryHeap, BinomialHeap
from copy import deepcopy as dc

__all__ = [
Expand Down Expand Up @@ -186,13 +187,17 @@ class PriorityQueue(object):
of priority queue.
The following implementations are supported,
'linked_list' -> Linked list implementation.
Optional, by default, 'linked_list' implementation
'binary_heap' -> Binary heap implementation.
'binomial_heap' -> Binomial heap implementation.
Doesn't support custom comparators, minimum
key data is extracted in every pop.
Optional, by default, 'binary_heap' implementation
is used.
comp: function
The comparator to be used while comparing priorities.
Must return a bool object.
By default, `lambda u, v: u > v` is used to compare
priorities i.e., maximum priority elements are extracted
By default, `lambda u, v: u < v` is used to compare
priorities i.e., minimum priority elements are extracted
by pop operation.
Examples
Expand All @@ -203,43 +208,65 @@ class PriorityQueue(object):
>>> pq.push(1, 2)
>>> pq.push(2, 3)
>>> pq.pop()
2
>>> pq2 = PriorityQueue(comp=lambda u, v: u < v)
1
>>> pq2 = PriorityQueue(comp=lambda u, v: u > v)
>>> pq2.push(1, 2)
>>> pq2.push(2, 3)
>>> pq2.pop()
1
2
References
==========
.. [1] https://en.wikipedia.org/wiki/Priority_queue#Naive_implementations
.. [1] https://en.wikipedia.org/wiki/Priority_queue
"""

def __new__(cls, implementation='linked_list', **kwargs):
def __new__(cls, implementation='binary_heap', **kwargs):
comp = kwargs.get("comp", lambda u, v: u < v)
if implementation == 'linked_list':
return LinkedListPriorityQueue(
kwargs.get("comp", lambda u, v: u > v)
)
return LinkedListPriorityQueue(comp)
elif implementation == 'binary_heap':
return BinaryHeapPriorityQueue(comp)
elif implementation == 'binomial_heap':
return BinomialHeapPriorityQueue()
else:
raise NotImplementedError(
"%s implementation is not currently supported "
"by priority queue.")

def push(self, value, priority):
"""
Pushes the value to the priority queue
according to the given priority.
value
Value to be pushed.
priority
Priority to be given to the value.
"""
raise NotImplementedError(
"This is an abstract method.")

def pop(self):
"""
Pops out the value from the priority queue.
"""
raise NotImplementedError(
"This is an abstract method.")

@property
def is_empty(self):
"""
Checks if the priority queue is empty.
"""
raise NotImplementedError(
"This is an abstract method.")

class LinkedListPriorityQueue(PriorityQueue):

__slots__ = ['items', 'comp']

def __new__(cls, comp=lambda u, v: u > v):
def __new__(cls, comp):
obj = object.__new__(cls)
obj.items = SinglyLinkedList()
obj.comp = comp
Expand All @@ -266,3 +293,45 @@ def pop(self):
@property
def is_empty(self):
return self.items.size == 0

class BinaryHeapPriorityQueue(PriorityQueue):

__slots__ = ['items']

def __new__(cls, comp):
obj = object.__new__(cls)
obj.items = BinaryHeap()
obj.items._comp = comp
return obj

def push(self, value, priority):
self.items.insert(priority, value)

def pop(self):
node = self.items.extract()
return node.data

@property
def is_empty(self):
return self.items.is_empty

class BinomialHeapPriorityQueue(PriorityQueue):

__slots__ = ['items']

def __new__(cls):
obj = object.__new__(cls)
obj.items = BinomialHeap()
return obj

def push(self, value, priority):
self.items.insert(priority, value)

def pop(self):
node = self.items.find_minimum()
self.items.delete_minimum()
return node.data

@property
def is_empty(self):
return self.items.is_empty
21 changes: 12 additions & 9 deletions pydatastructs/miscellaneous_data_structures/tests/test_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,15 @@ def test_PriorityQueue():
assert _check_type(pq1, LinkedListPriorityQueue) is True
assert raises(NotImplementedError, lambda: Queue(implementation=''))

def test_LinkedListPriorityQueue():
pq1 = PriorityQueue(implementation='linked_list')
pq1.push(1, 2)
pq1.push(2, 3)
pq1.push(3, 4)
assert pq1.pop() == 3
assert pq1.pop() == 2
assert pq1.pop() == 1
assert raises(IndexError, lambda: pq1.pop())
def test_ImplementationPriorityQueue():
impls = ['linked_list', 'binomial_heap', 'binary_heap']
for impl in impls:
pq1 = PriorityQueue(implementation=impl)
pq1.push(1, 2)
pq1.push(2, 3)
pq1.push(3, 4)
assert pq1.pop() == 1
assert pq1.pop() == 2
assert pq1.pop() == 3
assert pq1.is_empty is True
assert raises(IndexError, lambda: pq1.pop())
11 changes: 9 additions & 2 deletions pydatastructs/trees/heaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def extract(self):
If the heap is empty.
"""
if self._last_pos_filled == -1:
return None
raise IndexError("Heap is empty.")
else:
element_to_be_extracted = TreeNode(self.heap[0].key, self.heap[0].data)
self._swap(0, self._last_pos_filled)
Expand All @@ -194,6 +194,13 @@ def __str__(self):
to_be_printed[i] = (node.key, node.data, children)
return str(to_be_printed)

@property
def is_empty(self):
"""
Checks if the heap is empty.
"""
return self.heap._last_pos_filled == -1


class BinaryHeap(DHeap):
"""
Expand Down Expand Up @@ -456,7 +463,7 @@ def find_minimum(self, **kwargs):
min_node: BinomialTreeNode
"""
if self.is_empty:
raise ValueError("Binomial heap is empty.")
raise IndexError("Binomial heap is empty.")
min_node = None
idx, min_idx = 0, None
for tree in self.root_list:
Expand Down
8 changes: 4 additions & 4 deletions pydatastructs/trees/tests/test_heaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def test_BinaryHeap():

max_heap = BinaryHeap(heap_property="max")

assert max_heap.extract() is None
assert raises(IndexError, lambda: max_heap.extract())

max_heap.insert(100, 100)
max_heap.insert(19, 19)
Expand Down Expand Up @@ -57,7 +57,7 @@ def test_BinaryHeap():
BinaryHeap(elements = non_TreeNode_elements, heap_property='min'))
def test_TernaryHeap():
max_heap = TernaryHeap(heap_property="max")
assert max_heap.extract() is None
assert raises(IndexError, lambda: max_heap.extract())
max_heap.insert(100, 100)
max_heap.insert(19, 19)
max_heap.insert(36, 36)
Expand Down Expand Up @@ -97,7 +97,7 @@ def test_TernaryHeap():
def test_DHeap():
assert raises(ValueError, lambda: DHeap(heap_property="none", d=4))
max_heap = DHeap(heap_property="max", d=5)
assert max_heap.extract() is None
assert raises(IndexError, lambda: max_heap.extract())
max_heap.insert(100, 100)
max_heap.insert(19, 19)
max_heap.insert(36, 36)
Expand Down Expand Up @@ -213,7 +213,7 @@ def bfs(heap):

# Testing BinomialHeap.insert
heap = BinomialHeap()
assert raises(ValueError, lambda: heap.find_minimum())
assert raises(IndexError, lambda: heap.find_minimum())
heap.insert(1, 1)
heap.insert(3, 3)
heap.insert(6, 6)
Expand Down

0 comments on commit a5a7ad9

Please sign in to comment.