-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathheap.py
More file actions
191 lines (175 loc) · 5.64 KB
/
Copy pathheap.py
File metadata and controls
191 lines (175 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
__author__ = 'zjb'
class Heap(object):
'''
Heap that orders by a given comparison function, default to less-than.
'''
__slots__ = ('data','size','lessfn')
def __init__(self,lessfn):
'''
Constructor takes a comparison function.
:param lessfn: Function that takes in two heap objects and returns true
if the first arg goes higher in the heap than the second
'''
self.data = []
self.size = 0
self.lessfn = lessfn
def __parent(self,loc):
'''
Helper function to compute the parent location of an index
:param loc: Index in the heap
:return: Index of parent
'''
return (loc-1)//2
def __bubbleUp(self,loc):
'''
Starts from the given location and moves the item at that spot
as far up the heap as necessary
:param loc: Place to start bubbling from
'''
while loc > 0 and \
self.lessfn(self.data[loc],self.data[self.__parent(loc)]):
self.data[loc], self.data[self.__parent(loc)] = \
self.data[self.__parent(loc)], self.data[loc]
loc = self.__parent(loc)
def __bubbleDown(self,loc):
'''
Starts from the given location and moves the item at that spot
as far down the heap as necessary
:param loc: Place to start bubbling from
'''
swapLoc = self.__smallest(loc)
while swapLoc != loc:
self.data[loc], self.data[swapLoc] = \
self.data[swapLoc], self.data[loc]
loc = swapLoc
swapLoc = self.__smallest(loc)
def __smallest(self,loc):
'''
Finds the "smallest" value of loc and loc's two children.
Correctly handles end-of-heap issues.
:param loc: Index
:return: index of smallest value
'''
ch1 = loc*2 + 1
ch2 = loc*2 + 2
if ch1 >= self.size:
return loc
if ch2 >= self.size:
if self.lessfn(self.data[loc],self.data[ch1]):
return loc
else:
return ch1
# now consider all 3
if self.lessfn(self.data[ch1],self.data[ch2]):
if self.lessfn(self.data[loc],self.data[ch1]):
return loc
else:
return ch1
else:
if self.lessfn(self.data[loc],self.data[ch2]):
return loc
else:
return ch2
def insert(self,item):
'''
Inserts an item into the heap.
:param item: Item to be inserted
'''
if self.size < len(self.data):
self.data[self.size] = item
else:
self.data.append(item)
self.size += 1
self.__bubbleUp(self.size-1)
def pop(self):
'''
Removes and returns top of the heap
:return: Item on top of the heap
'''
retjob = self.data[0]
self.size -= 1
# if we are popping the only element, assignment will fail,
# but bubbling is unnecessary, so:
if self.size > 0:
self.data[0] = self.data.pop(self.size)
self.__bubbleDown(0)
return retjob
def __len__(self):
'''
Defining the "length" of a data structure also allows it to be
used as a boolean value!
:return: size of heap
'''
return self.size
def __str__(self):
ret = ""
for item in range(self.size):
ret += str(self.data[item]) + " "
return ret
def namecmp(n1, n2):
'''
Simple comparison function as an example.
Assumes each name is (first, last) tuple
:param n1: Name
:param n2: Other name
:return: True if n1 comes before n2
'''
return n1[1] < n2[1]
def main():
# here's a min heap (comparison is less than)
print("Numerical min heap");
minh = Heap(lambda x,y: x<y)
print("Array contents:",minh.data)
print("Insert 5, 3, 7, 2.")
for num in (5,3,7,2):
minh.insert(num)
print("Heap is now: " + str(minh))
print("Array contents:",minh.data)
print("Pop.")
print(minh.pop())
print("Array contents:",minh.data)
print("Insert 1, 8.")
minh.insert(1)
minh.insert(8)
print("Heap is now: " + str(minh))
print("Array contents:",minh.data)
print("Emptying heap.")
while minh:
print(minh.pop())
print("Array contents:",minh.data)
# here's a max heap
print("\nNumerical max heap");
maxh = Heap(lambda x,y: x > y)
print("Insert 4, 6, 10, 2, -1, 3.")
for num in (4,6,10,2,-1,3):
maxh.insert(num)
print("Emptying max heap.")
while maxh:
print(maxh.pop())
print("Insert 5, 7, 11, 3, -2, 4.")
for num in 5,7,11,3,-2,4:
maxh.insert(num)
print("Emptying max heap.")
while maxh:
print(maxh.pop())
# a heap of names, for some reason?
print("\nString min heap");
nameheap = Heap(namecmp)
for name in ('Sean','Strout'), ('Zack','Butler'), \
('James','Heliotis'), ('Alan','Turing'):
print("Insert",name)
nameheap.insert(name)
print("Pop.")
print(nameheap.pop())
print("Pop.")
print(nameheap.pop())
print("Pop.")
print(nameheap.pop())
for name in ('Ada','Lovelace'), ('Grace','Hopper'):
print("Insert",name)
nameheap.insert(name)
print("Emptying string heap.")
while nameheap:
print(nameheap.pop())
if __name__ == '__main__':
main()