Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-110067: Make max heap methods public and add missing ones#130725

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
encukou merged 27 commits intopython:mainfromStanFromIreland:add-heapq-max
May 5, 2025
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
Show all changes
27 commits
Select commitHold shift + click to select a range
eccf484
Initial addition
StanFromIrelandMar 1, 2025
beaf915
Add C imp
StanFromIrelandMar 1, 2025
c143ae2
Benedikts suggestions
StanFromIrelandMar 1, 2025
167525d
Benedikts suggestions
StanFromIrelandMar 1, 2025
1b0b6f3
Update Modules/_heapqmodule.c with Benedikts suggestion
StanFromIrelandMar 1, 2025
fc46707
Fix mistake (extra underscores)
StanFromIrelandMar 1, 2025
f4fd94a
Benedikt's requested changes
StanFromIrelandMar 1, 2025
cebbc88
Missed one of Benedikt's requested changes
StanFromIrelandMar 1, 2025
3cde6c6
Benedikts suggestion
StanFromIrelandMar 1, 2025
5d2d387
Benedikts Suggestions
StanFromIrelandMar 2, 2025
a499cd4
Fix doc warnings
StanFromIrelandMar 2, 2025
abe0a95
Improve entries
StanFromIrelandMar 2, 2025
3561206
Address some of Petr's suggestions
StanFromIrelandMar 10, 2025
8fd1a03
Clean up and add missing
StanFromIrelandMar 10, 2025
8ab97c2
Update Doc/library/heapq.rst
StanFromIrelandMar 17, 2025
623cae7
Merge branch 'main' into add-heapq-max
StanFromIrelandApr 25, 2025
81db251
Sort and add missing C implementation
StanFromIrelandMay 2, 2025
38cbf13
Petr's list suggestion
StanFromIrelandMay 2, 2025
b6f4db4
heappushpop_max fixup
StanFromIrelandMay 2, 2025
61c9285
Improve test
StanFromIrelandMay 4, 2025
ebe00dc
Switch to <
StanFromIrelandMay 5, 2025
bc0dd66
Clean up test
StanFromIrelandMay 5, 2025
988b2d3
Reword the docs
encukouMay 5, 2025
6efd70c
Add max-heap variants for the other tests
encukouMay 5, 2025
4ba533b
Apply suggestions from code review
encukouMay 5, 2025
160bc35
Merge pull request #1 from encukou/add-heapq-max
StanFromIrelandMay 5, 2025
742c46c
final touchups
StanFromIrelandMay 5, 2025
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
40 changes: 40 additions & 0 deletionsDoc/library/heapq.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -82,6 +82,46 @@
on the heap.


..function::heappush_max(heap, item)

Push the value *item* onto the *heap*, maintaining the heap invariant.


..function::heappop_max(heap)

Pop and return the largest item from the *heap*, maintaining the heap
invariant. If the heap is empty,:exc:`IndexError` is raised. To access the
largest item without popping it, use ``heap[0]``.


..function::heappushpop_max(heap, item)

Push *item* on the heap, then pop and return the largest item from the
*heap*. The combined action runs more efficiently than:func:`heappush_max`
followed by a separate call to:func:`heappop_max`.


..function::heapify_max(x)

Transform list *x* into a max heap, in-place, in linear time.


..function::heapreplace(heap, item)

Check warning on line 109 in Doc/library/heapq.rst

View workflow job for this annotation

GitHub Actions/ Docs / Docs

duplicate object description of heapq.heapreplace, other instance in library/heapq, use :no-index: for one of them

Pop and return the smallest item from the *heap*, and also push the new *item*.
The heap size doesn't change. If the heap is empty,:exc:`IndexError` is raised.

This one step operation is more efficient than a:func:`heappop` followed by
:func:`heappush` and can be more appropriate when using a fixed-size heap.
The pop/push combination always returns an element from the heap and replaces
it with *item*.

The value returned may be larger than the *item* added. If that isn't
desired, consider using:func:`heappushpop` instead. Its push/pop
combination returns the smaller of the two values, leaving the larger value
on the heap.


The module also offers three general purpose functions based on heaps.


Expand Down
38 changes: 25 additions & 13 deletionsLib/heapq.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -178,7 +178,7 @@ def heapify(x):
for i in reversed(range(n//2)):
_siftup(x, i)

def_heappop_max(heap):
defheappop_max(heap):
"""Maxheap version of a heappop."""
lastelt = heap.pop() # raises appropriate IndexError if heap is empty
if heap:
Expand All@@ -188,14 +188,26 @@ def _heappop_max(heap):
return returnitem
return lastelt

def_heapreplace_max(heap, item):
defheapreplace_max(heap, item):
"""Maxheap version of a heappop followed by a heappush."""
returnitem = heap[0] # raises appropriate IndexError if heap is empty
heap[0] = item
_siftup_max(heap, 0)
return returnitem

def _heapify_max(x):
def heappush_max(heap, item):
"""Maxheap version of a heappush."""
heap.append(item)
_siftdown_max(heap, 0, len(heap)-1)

def heappushpop_max(heap, item):
"""Maxheap fast version of a heappush followed by a heappop."""
if heap and heap[0] < item:
item, heap[0] = heap[0], item
_siftup_max(heap, 0)
return item

def heapify_max(x):
"""Transform list into a maxheap, in-place, in O(len(x)) time."""
n = len(x)
for i in reversed(range(n//2)):
Expand DownExpand Up@@ -335,9 +347,9 @@ def merge(*iterables, key=None, reverse=False):
h_append = h.append

if reverse:
_heapify =_heapify_max
_heappop =_heappop_max
_heapreplace =_heapreplace_max
_heapify =heapify_max
_heappop =heappop_max
_heapreplace =heapreplace_max
direction = -1
else:
_heapify = heapify
Expand DownExpand Up@@ -490,10 +502,10 @@ def nsmallest(n, iterable, key=None):
result = [(elem, i) for i, elem in zip(range(n), it)]
if not result:
return result
_heapify_max(result)
heapify_max(result)
top = result[0][0]
order = n
_heapreplace =_heapreplace_max
_heapreplace =heapreplace_max
for elem in it:
if elem < top:
_heapreplace(result, (elem, order))
Expand All@@ -507,10 +519,10 @@ def nsmallest(n, iterable, key=None):
result = [(key(elem), i, elem) for i, elem in zip(range(n), it)]
if not result:
return result
_heapify_max(result)
heapify_max(result)
top = result[0][0]
order = n
_heapreplace =_heapreplace_max
_heapreplace =heapreplace_max
for elem in it:
k = key(elem)
if k < top:
Expand DownExpand Up@@ -584,15 +596,15 @@ def nlargest(n, iterable, key=None):
except ImportError:
pass
try:
from _heapq import_heapreplace_max
from _heapq importheapreplace_max
except ImportError:
pass
try:
from _heapq import_heapify_max
from _heapq importheapify_max
except ImportError:
pass
try:
from _heapq import_heappop_max
from _heapq importheappop_max
except ImportError:
pass

Expand Down
71 changes: 66 additions & 5 deletionsLib/test/test_heapq.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,7 +14,7 @@
# _heapq.nlargest/nsmallest are saved in heapq._nlargest/_smallest when
# _heapq is imported, so check them there
func_names = ['heapify', 'heappop', 'heappush', 'heappushpop', 'heapreplace',
'_heappop_max', '_heapreplace_max', '_heapify_max']
'heappop_max', 'heapreplace_max', 'heapify_max']

class TestModules(TestCase):
def test_py_functions(self):
Expand All@@ -23,7 +23,7 @@ def test_py_functions(self):

@skipUnless(c_heapq, 'requires _heapq')
def test_c_functions(self):
for fname infunc_names:
for fname in['heapify', 'heappop', 'heappush', 'heappushpop', 'heapreplace']:
self.assertEqual(getattr(c_heapq, fname).__module__, '_heapq')


Expand DownExpand Up@@ -74,13 +74,47 @@ def test_push_pop(self):
except AttributeError:
pass

def test_max_push_pop(self):
# 1) Push 256 random numbers and pop them off, verifying all's OK.
heap = []
data = []
self.check_max_invariant(heap)
for i in range(256):
item = random.random()
data.append(item)
self.module.heappush_max(heap, item)
self.check_max_invariant(heap)
results = []
while heap:
item = self.module.heappop_max(heap)
self.check_max_invariant(heap)
results.append(item)
data_sorted = data[:]
data_sorted.sort(reverse=True)

self.assertEqual(data_sorted, results)
# 2) Check that the invariant holds for a sorted array
self.check_max_invariant(results)

self.assertRaises(TypeError, self.module.heappush, [])
try:
self.assertRaises(TypeError, self.module.heappush, None, None)
self.assertRaises(TypeError, self.module.heappop, None)
except AttributeError:
pass

def check_invariant(self, heap):
# Check the heap invariant.
for pos, item in enumerate(heap):
if pos: # pos 0 has no parent
parentpos = (pos-1) >> 1
self.assertTrue(heap[parentpos] <= item)

def check_max_invariant(self, heap):
for pos in range(1, len(heap)):
parentpos = (pos - 1) >> 1
self.assertTrue(heap[parentpos] >= heap[pos])

def test_heapify(self):
for size in list(range(30)) + [20000]:
heap = [random.random() for dummy in range(size)]
Expand All@@ -89,6 +123,14 @@ def test_heapify(self):

self.assertRaises(TypeError, self.module.heapify, None)

def test_heapify_max(self):
for size in list(range(30)) + [20000]:
heap = [random.random() for dummy in range(size)]
self.module.heapify_max(heap)
self.check_max_invariant(heap)

self.assertRaises(TypeError, self.module.heapify, None)

def test_naive_nbest(self):
data = [random.randrange(2000) for i in range(1000)]
heap = []
Expand DownExpand Up@@ -153,12 +195,31 @@ def test_heappushpop(self):
x = self.module.heappushpop(h, 11)
self.assertEqual((h, x), ([11], 10))

def test_heappushpop_max(self):
h = []
x = self.module.heappushpop_max(h, 10)
self.assertEqual((h, x), ([], 10))

h = [10]
x = self.module.heappushpop_max(h, 10.0)
self.assertEqual((h, x), ([10], 10.0))
self.assertEqual(type(h[0]), int)
self.assertEqual(type(x), float)

h = [10]
x = self.module.heappushpop_max(h, 11)
self.assertEqual((h, x), ([11], 10))

h = [10]
x = self.module.heappushpop_max(h, 9)
self.assertEqual((h, x), ([10], 9))

def test_heappop_max(self):
#_heapop_max has an optimization for one-item lists which isn't
#heapop_max has an optimization for one-item lists which isn't
# covered in other tests, so test that case explicitly here
h = [3, 2]
self.assertEqual(self.module._heappop_max(h), 3)
self.assertEqual(self.module._heappop_max(h), 2)
self.assertEqual(self.module.heappop_max(h), 3)
self.assertEqual(self.module.heappop_max(h), 2)

def test_heapsort(self):
# Exercise everything with repeated heapsort checks
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
Make max heap functions public.
Loading

[8]ページ先頭

©2009-2025 Movatter.jp