# HG changeset patch # User prashant # Date 1394698608 -19800 # Branch 2.7 # Node ID b774fc7e6d2efb1194ef378ee750393021c8752b # Parent 1763e27a182d571cc3a428c71085bb86b3d895b5 Support comparator in heapq push/pop/reaplace functions. diff -r 1763e27a182d -r b774fc7e6d2e Lib/heapq.py --- a/Lib/heapq.py Wed Mar 12 21:51:52 2014 -0500 +++ b/Lib/heapq.py Thu Mar 13 13:46:48 2014 +0530 @@ -127,7 +127,7 @@ """ __all__ = ['heappush', 'heappop', 'heapify', 'heapreplace', 'merge', - 'nlargest', 'nsmallest', 'heappushpop'] + 'nlargest', 'nsmallest', 'heappushpop', 'cmp_gt'] from itertools import islice, count, imap, izip, tee, chain from operator import itemgetter @@ -137,24 +137,31 @@ # In Py3.x, only __lt__ will be called. return (x < y) if hasattr(x, '__lt__') else (not y <= x) -def heappush(heap, item): +def cmp_gt(x, y): + # Use __lt__ if available; otherwise, try __le__. + # In Py3.x, only __lt__ will be called. + return (y < x) if hasattr(y, '__lt__') else (not x <= y) + +def heappush(heap, item, comparator=cmp_lt): """Push item onto heap, maintaining the heap invariant.""" heap.append(item) - _siftdown(heap, 0, len(heap)-1) + _siftdown(heap, 0, len(heap)-1, comparator) -def heappop(heap): - """Pop the smallest item off the heap, maintaining the heap invariant.""" +def heappop(heap, comparator=cmp_lt): + """Pop the smallest or largest item off the heap based on comparator(default is smallest), + maintaining the heap invariant.""" lastelt = heap.pop() # raises appropriate IndexError if heap is empty if heap: returnitem = heap[0] heap[0] = lastelt - _siftup(heap, 0) + _siftup(heap, 0, comparator) else: returnitem = lastelt return returnitem -def heapreplace(heap, item): - """Pop and return the current smallest value, and add the new item. +def heapreplace(heap, item, comparator=cmp_lt): + """Pop and return the current smallest or largest value based on + comparator(default is smallest), and add the new item. This is more efficient than heappop() followed by heappush(), and can be more appropriate when using a fixed-size heap. Note that the value @@ -166,17 +173,17 @@ """ returnitem = heap[0] # raises appropriate IndexError if heap is empty heap[0] = item - _siftup(heap, 0) + _siftup(heap, 0, comparator) return returnitem -def heappushpop(heap, item): +def heappushpop(heap, item, comparator=cmp_lt): """Fast version of a heappush followed by a heappop.""" - if heap and cmp_lt(heap[0], item): + if heap and comparator(heap[0], item): item, heap[0] = heap[0], item - _siftup(heap, 0) + _siftup(heap, 0, comparator) return item -def heapify(x): +def heapify(x, comparator=cmp_lt): """Transform list into a heap, in-place, in O(len(x)) time.""" n = len(x) # Transform bottom-up. The largest index there's any point to looking at @@ -185,7 +192,7 @@ # j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is # (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1. for i in reversed(xrange(n//2)): - _siftup(x, i) + _siftup(x, i, comparator) def _heappushpop_max(heap, item): """Maxheap version of a heappush followed by a heappop.""" @@ -239,14 +246,14 @@ # 'heap' is a heap at all indices >= startpos, except possibly for pos. pos # is the index of a leaf with a possibly out-of-order value. Restore the # heap invariant. -def _siftdown(heap, startpos, pos): +def _siftdown(heap, startpos, pos, comparator=cmp_lt): newitem = heap[pos] # Follow the path to the root, moving parents down until finding a place # newitem fits. while pos > startpos: parentpos = (pos - 1) >> 1 parent = heap[parentpos] - if cmp_lt(newitem, parent): + if comparator(newitem, parent): heap[pos] = parent pos = parentpos continue @@ -292,7 +299,7 @@ # heappop() compares): list.sort() is (unsurprisingly!) more efficient # for sorting. -def _siftup(heap, pos): +def _siftup(heap, pos, comparator=cmp_lt): endpos = len(heap) startpos = pos newitem = heap[pos] @@ -301,7 +308,7 @@ while childpos < endpos: # Set childpos to index of smaller child. rightpos = childpos + 1 - if rightpos < endpos and not cmp_lt(heap[childpos], heap[rightpos]): + if rightpos < endpos and not comparator(heap[childpos], heap[rightpos]): childpos = rightpos # Move the smaller child up. heap[pos] = heap[childpos] @@ -310,7 +317,7 @@ # The leaf at pos is empty now. Put newitem there, and bubble it up # to its final resting place (by sifting its parents down). heap[pos] = newitem - _siftdown(heap, startpos, pos) + _siftdown(heap, startpos, pos, comparator) def _siftdown_max(heap, startpos, pos): 'Maxheap variant of _siftdown'