Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5778de4
Add files for priorityq
jonathanstallings Jul 5, 2015
10a05e5
Sketch out methods. refs #10
jonathanstallings Jul 5, 2015
91e641a
Change node class name
jonathanstallings Jul 5, 2015
e90c100
Set default priority level to None
jonathanstallings Jul 5, 2015
b7cdf15
Add some QNode tests. refs #11
jonathanstallings Jul 5, 2015
bee27f2
Add tests for insert method
jonathanstallings Jul 5, 2015
a959390
Complete first pass simple tests
jonathanstallings Jul 5, 2015
f8e4334
Add notes to sketch for priorityq. refs #10
jonathanstallings Jul 5, 2015
44bc17c
Add notes to tests. refs #11
jonathanstallings Jul 5, 2015
e55cccb
Add to notes
jonathanstallings Jul 5, 2015
10c22e7
Fix error in test fixture
jonathanstallings Jul 5, 2015
c2a2da2
First pass at script
jonathanstallings Jul 5, 2015
efffab3
Fill out methods
jonathanstallings Jul 5, 2015
eb4fb77
Fix test error
jonathanstallings Jul 5, 2015
46582ba
Complete first pass of script
jonathanstallings Jul 5, 2015
f513c57
Add pretty printing of node val and priority.
jonathanstallings Jul 5, 2015
784ea9b
Improve docstrings
jonathanstallings Jul 5, 2015
9184eb5
Change wording in docstring
jonathanstallings Jul 5, 2015
ff88ee3
Improve docstrings
jonathanstallings Jul 5, 2015
cca2904
Start tracking insertion order after priority
jonathanstallings Jul 5, 2015
36c1769
Make priority and order explicit in tests
jonathanstallings Jul 5, 2015
4a898a5
Improve pretty printing
jonathanstallings Jul 5, 2015
3691c3b
Improve tests
jonathanstallings Jul 5, 2015
439d784
Fix docstring for queue order tracking
jonathanstallings Jul 5, 2015
85aa656
Remove commment from test
jonathanstallings Jul 5, 2015
0a5c665
Change pop and peek return to value instead of QNode
jonathanstallings Jul 5, 2015
2303015
Use '==' instead of 'is' where appropriate
jonathanstallings Jul 5, 2015
2c5f347
Refactor __eq__
jonathanstallings Jul 5, 2015
b661900
Remove unneeded _count attribute
jonathanstallings Jul 5, 2015
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
106 changes: 106 additions & 0 deletions priorityq.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from __future__ import unicode_literals
from functools import total_ordering

from binary_heap import BinaryHeap


@total_ordering # Will build out the remaining comparison methods
class QNode(object):
"""A class for a queue node."""
def __init__(self, val, priority=None, order=None):
"""Initialize a QNode with a value and an optional priority.

args:
val: the value to store
priority: an integer with 0 being most important
order: integer to store queue insertion order
"""
self.val = val
self.priority = priority
self.order = order

def __repr__(self):
"""Print representation of node."""
return "{val}".format(val=self.val)

def __str__(self):
"""Pretty print node value and priority."""
return "Value:{val}, Order:{o} Priority:{p}".format(
val=self.val, o=self.order, p=self.priority
)

def __eq__(self, other):
"""Overloads equality comparison to check priority, then order."""
if self.priority == other.priority:
return self.order == other.order
else:
return self.priority == other.priority

def __lt__(self, other):
"""Overloads lesser than comparison to check priority, then order."""
if self.priority == other.priority:
return self.order < other.order
elif self.priority is None:
return False
elif other.priority is None:
return True
else:
return self.priority < other.priority


class PriorityQ(object):
"""A class for a priority queue."""
def __init__(self, iterable=()):
"""Initialize a priority queue, optionally with items from iterable.

The items in the priority queue are stored in a binary minheap. Items
are first sorted by priority, then queue insertion order. Priority is
expressed as an integer with 0 being the most important.

args:
iterable: an optional iterable to add to the priority queue. Items
added this way will be given a priority of None.
"""
self.heap = BinaryHeap(iterable=())
for item in iterable:
self.insert(item)

def __repr__(self):
return repr(self.heap)

def __len__(self):
return len(self.heap)

def __iter__(self):
return iter(self.heap)

def __getitem__(self, index):
return self.heap[index]

def __setitem__(self, index, value):
self.heap[index] = value

def insert(self, item, priority=None):
"""Insert an item into the priority queue.

If the item is a QNode object, it will be added tracking queue order.
If not, a new QNode object is created to hold the item with queue order
and optional priority assigned.

args:
item: the item to add (QNode or other value)
priority: the optional integer priority (0 is most important)
"""
if isinstance(item, QNode):
item.order = len(self)
self.heap.push(item)
else:
self.heap.push(QNode(item, priority=priority, order=len(self)))

def pop(self):
"""Remove and return the most important item from the queue."""
return self.heap.pop().val

def peek(self):
"""Return the most important item from queue without removal."""
return self.heap[0].val
124 changes: 124 additions & 0 deletions test_priorityq.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from __future__ import unicode_literals
import pytest

from priorityq import PriorityQ, QNode


@pytest.fixture()
def QNode_list():
QNode_list = [
QNode(10),
QNode(5, priority=2),
QNode(100, priority=1)
]
return QNode_list


@pytest.fixture()
def base_pqueue(QNode_list):
return PriorityQ(QNode_list)


def test_QNode_init_no_priority():
node1 = QNode(10)
assert node1.val == 10
assert node1.priority is None


def test_QNode_init_with_priority():
node1 = QNode(10, priority=0)
assert node1.val == 10
assert node1.priority == 0


def test_QNode_order_comparison():
node1 = QNode(10, order=1)
node2 = QNode(5, order=2)
assert node1 < node2


def test_QNode_priority_comparison():
node1 = QNode(10, priority=0)
node2 = QNode(10)
assert node1 < node2


def test_QNode_equal_priority_comparison():
node1 = QNode(10, priority=1, order=1)
node2 = QNode(5, priority=1, order=2)
assert node1 < node2


def test_QNode_equality_comparison():
node1 = QNode(10, priority=10)
node2 = QNode(10, priority=10)
assert node1 == node2


def test_PriorityQ_init_empty():
pqueue = PriorityQ()
assert isinstance(pqueue, PriorityQ)
assert len(pqueue) == 0


def test_PriorityQ_init_iterable_no_QNodes():
pqueue = PriorityQ([10, 9, 8, 7, 6, 5])
assert len(pqueue) == 6
assert pqueue[0].val == 10
assert pqueue[0].priority is None


def test_PriorityQ_init_iterable_with_QNodes(QNode_list):
pqueue = PriorityQ(QNode_list)
assert len(pqueue) == 3
assert pqueue[0].val == 100
assert pqueue[0].priority == 1


def test_insert_item_not_QNode_to_empty():
queue = PriorityQ()
queue.insert(50)
assert len(queue) == 1
assert queue[0].val == 50
assert queue[0].priority is None


def test_insert_item_QNode_to_empty():
node1 = QNode(10, priority=0)
pqueue = PriorityQ()
pqueue.insert(node1)
assert len(pqueue) == 1
assert pqueue[0].val == 10
assert pqueue[0].priority == 0


def test_insert_item_not_QNode_to_filled(base_pqueue):
base_pqueue.insert(500, priority=0)
assert len(base_pqueue) == 4
assert base_pqueue[0].val == 500
assert base_pqueue[0].order == 3
assert base_pqueue[0].priority == 0


def test_insert_QNode_to_filled(base_pqueue):
node1 = QNode(10, priority=0)
base_pqueue.insert(node1)
assert len(base_pqueue) == 4
assert base_pqueue[0].val == 10
assert base_pqueue[0].order == 3
assert base_pqueue[0].priority == 0


def test_pop(base_pqueue):
top_priority = QNode(9000, priority=0)
length = len(base_pqueue)
base_pqueue.insert(top_priority)
assert base_pqueue.pop() == top_priority.val
assert len(base_pqueue) == length


def test_peek(base_pqueue):
top_priority = QNode(9000, priority=0)
base_pqueue.insert(top_priority)
assert base_pqueue.peek() == top_priority.val
assert base_pqueue[0] is top_priority