Skip to content

Commit 5cf0fef

Browse files
amicksOmkarPathak
authored andcommitted
Implement heap data structure and unit test. (#20)
* Add insert function for heap. * Implement pop for heap. * Polish comments * Change docstrings for consistency. Add get_code function. * Fix SyntaxError on line 36. Defines source code encoding as Unicode to conform to PEP 263. * Add heap unit test.
1 parent 5ff3a59 commit 5cf0fef

File tree

2 files changed

+113
-1
lines changed

2 files changed

+113
-1
lines changed

pygorithm/data_structures/heap.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Author: ALLSTON MICKEY
2+
# Created On: 11th August 2017
3+
4+
from queue import Queue
5+
6+
# min-heap implementation as priority queue
7+
class Heap(Queue):
8+
def parent_idx(self, idx):
9+
return idx / 2
10+
11+
def left_child_idx(self, idx):
12+
return (idx * 2) + 1
13+
14+
def right_child_idx(self, idx):
15+
return (idx * 2) + 2
16+
17+
def insert(self, data):
18+
super(Heap, self).enqueue(data)
19+
if self.rear >= 1: # heap may need to be fixed
20+
self.heapify_up()
21+
22+
def heapify_up(self):
23+
'''
24+
Start at the end of the tree (first enqueued item).
25+
26+
Compare the rear item to its parent, swap if
27+
the parent is larger than the child (min-heap property).
28+
Repeat until the min-heap property is met.
29+
'''
30+
child = self.rear
31+
parent = self.parent_idx(child)
32+
while self.queue[child] < self.queue[self.parent_idx(child)]:
33+
# Swap (sift up) and update child:parent relation
34+
self.queue[child], self.queue[parent] = self.queue[parent], self.queue[child]
35+
child = parent
36+
parent = self.parent_idx(child)
37+
38+
def pop(self):
39+
''' Removes the lowest value element (highest priority) from the heap '''
40+
min = self.dequeue()
41+
if self.rear >= 1: # heap may need to be fixed
42+
self.heapify_down()
43+
return min
44+
45+
def favorite(self, parent):
46+
''' Determines which child has the highest priority by 3 cases '''
47+
left = self.left_child_idx(parent)
48+
right = self.right_child_idx(parent)
49+
50+
if left <= self.rear and right <= self.rear: # case 1: both nodes exist
51+
if self.queue[left] <= self.queue[right]:
52+
return left
53+
else:
54+
return right
55+
elif left <= self.rear: # case 2: only left exists
56+
return left
57+
else: # case 3: no children (if left doesn't exist, neither can the right)
58+
return None
59+
60+
def heapify_down(self):
61+
'''
62+
Select the root and sift down until min-heap property is met.
63+
64+
While a favorite child exists, and that child is smaller
65+
than the parent, swap them (sift down).
66+
'''
67+
cur = ROOT = 0 # start at the root
68+
fav = self.favorite(cur) # determine favorite child
69+
while self.queue[fav] is not None:
70+
if self.queue[cur] > self.queue[fav]:
71+
# Swap (sift down) and update parent:favorite relation
72+
fav = self.favorite(cur)
73+
self.queue[cur], self.queue[fav] = self.queue[fav], self.queue[cur]
74+
cur = fav
75+
else:
76+
return
77+
78+
def get_code(self):
79+
import inspect
80+
return inspect.getsource(Heap)
81+

tests/test_data_structure.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
# -*- coding: utf-8 -*-
12
import unittest
23

34
from pygorithm.data_structures import (
45
stack,
56
queue,
67
linked_list,
7-
tree)
8+
tree,
9+
heap)
810

911
class TestStack(unittest.TestCase):
1012
def test_stack(self):
@@ -131,5 +133,34 @@ def test_binary_search_tree(self):
131133

132134
self.assertTrue(root.find(8))
133135

136+
class TestHeap(unittest.TestCase):
137+
def test_heap(self):
138+
myHeap = heap.Heap(limit = 4)
139+
myHeap.insert(2) # [2]
140+
myHeap.insert(10) # [2, 10]
141+
myHeap.insert(12) # [2, 10, 12]
142+
myHeap.insert(3) # [2, 3, 10, 12]
143+
144+
expectedResult = [2, 3, 10, 12]
145+
self.assertEqual(myHeap.queue(), expectedResult)
146+
147+
self.assertEqual(myHeap.pop(), 2)
148+
expectedResult = [3, 10, 12]
149+
self.assertEqual(myHeap.queue(), expectedResult)
150+
151+
self.assertEqual(myHeap.pop(), 3)
152+
expectedResult = [10, 12]
153+
self.assertEqual(myHeap.queue(), expectedResult)
154+
155+
self.assertEqual(myHeap.pop(), 10)
156+
expectedResult = [12]
157+
self.assertEqual(myHeap.queue(), expectedResult)
158+
159+
self.assertEqual(myHeap.pop(), 12)
160+
expectedResult = []
161+
self.assertEqual(myHeap.queue(), expectedResult)
162+
163+
self.assertTrue(myHeap.is_empty())
164+
134165
if __name__ == '__main__':
135166
unittest.main()

0 commit comments

Comments
 (0)