Commit 6d7702ec authored by Raymond Hettinger's avatar Raymond Hettinger

Implement heapq in terms of less-than (to match list.sort()).

parent adff65bc
...@@ -167,7 +167,7 @@ def heapreplace(heap, item): ...@@ -167,7 +167,7 @@ def heapreplace(heap, item):
def heappushpop(heap, item): def heappushpop(heap, item):
"""Fast version of a heappush followed by a heappop.""" """Fast version of a heappush followed by a heappop."""
if heap and item > heap[0]: if heap and heap[0] < item:
item, heap[0] = heap[0], item item, heap[0] = heap[0], item
_siftup(heap, 0) _siftup(heap, 0)
return item return item
...@@ -240,10 +240,11 @@ def _siftdown(heap, startpos, pos): ...@@ -240,10 +240,11 @@ def _siftdown(heap, startpos, pos):
while pos > startpos: while pos > startpos:
parentpos = (pos - 1) >> 1 parentpos = (pos - 1) >> 1
parent = heap[parentpos] parent = heap[parentpos]
if parent <= newitem: if newitem < parent:
break heap[pos] = parent
heap[pos] = parent pos = parentpos
pos = parentpos continue
break
heap[pos] = newitem heap[pos] = newitem
# The child indices of heap index pos are already heaps, and we want to make # The child indices of heap index pos are already heaps, and we want to make
...@@ -294,7 +295,7 @@ def _siftup(heap, pos): ...@@ -294,7 +295,7 @@ def _siftup(heap, pos):
while childpos < endpos: while childpos < endpos:
# Set childpos to index of smaller child. # Set childpos to index of smaller child.
rightpos = childpos + 1 rightpos = childpos + 1
if rightpos < endpos and heap[rightpos] <= heap[childpos]: if rightpos < endpos and not heap[childpos] < heap[rightpos]:
childpos = rightpos childpos = rightpos
# Move the smaller child up. # Move the smaller child up.
heap[pos] = heap[childpos] heap[pos] = heap[childpos]
......
...@@ -36,6 +36,9 @@ Core and Builtins ...@@ -36,6 +36,9 @@ Core and Builtins
Extension Modules Extension Modules
----------------- -----------------
- The heapq module does comparisons using LT instead of LE. This
makes its implementation match that used by list.sort().
- Issue #2819: add full-precision summation function to math module, - Issue #2819: add full-precision summation function to math module,
based on Hettinger's ASPN Python Cookbook recipe. based on Hettinger's ASPN Python Cookbook recipe.
......
...@@ -28,12 +28,12 @@ _siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos) ...@@ -28,12 +28,12 @@ _siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
while (pos > startpos){ while (pos > startpos){
parentpos = (pos - 1) >> 1; parentpos = (pos - 1) >> 1;
parent = PyList_GET_ITEM(heap, parentpos); parent = PyList_GET_ITEM(heap, parentpos);
cmp = PyObject_RichCompareBool(parent, newitem, Py_LE); cmp = PyObject_RichCompareBool(newitem, parent, Py_LT);
if (cmp == -1) { if (cmp == -1) {
Py_DECREF(newitem); Py_DECREF(newitem);
return -1; return -1;
} }
if (cmp == 1) if (cmp == 0)
break; break;
Py_INCREF(parent); Py_INCREF(parent);
Py_DECREF(PyList_GET_ITEM(heap, pos)); Py_DECREF(PyList_GET_ITEM(heap, pos));
...@@ -69,14 +69,14 @@ _siftup(PyListObject *heap, Py_ssize_t pos) ...@@ -69,14 +69,14 @@ _siftup(PyListObject *heap, Py_ssize_t pos)
rightpos = childpos + 1; rightpos = childpos + 1;
if (rightpos < endpos) { if (rightpos < endpos) {
cmp = PyObject_RichCompareBool( cmp = PyObject_RichCompareBool(
PyList_GET_ITEM(heap, rightpos),
PyList_GET_ITEM(heap, childpos), PyList_GET_ITEM(heap, childpos),
Py_LE); PyList_GET_ITEM(heap, rightpos),
Py_LT);
if (cmp == -1) { if (cmp == -1) {
Py_DECREF(newitem); Py_DECREF(newitem);
return -1; return -1;
} }
if (cmp == 1) if (cmp == 0)
childpos = rightpos; childpos = rightpos;
} }
/* Move the smaller child up. */ /* Move the smaller child up. */
...@@ -214,10 +214,10 @@ heappushpop(PyObject *self, PyObject *args) ...@@ -214,10 +214,10 @@ heappushpop(PyObject *self, PyObject *args)
return item; return item;
} }
cmp = PyObject_RichCompareBool(item, PyList_GET_ITEM(heap, 0), Py_LE); cmp = PyObject_RichCompareBool(PyList_GET_ITEM(heap, 0), item, Py_LT);
if (cmp == -1) if (cmp == -1)
return NULL; return NULL;
if (cmp == 1) { if (cmp == 0) {
Py_INCREF(item); Py_INCREF(item);
return item; return item;
} }
...@@ -270,6 +270,7 @@ nlargest(PyObject *self, PyObject *args) ...@@ -270,6 +270,7 @@ nlargest(PyObject *self, PyObject *args)
{ {
PyObject *heap=NULL, *elem, *iterable, *sol, *it, *oldelem; PyObject *heap=NULL, *elem, *iterable, *sol, *it, *oldelem;
Py_ssize_t i, n; Py_ssize_t i, n;
int cmp;
if (!PyArg_ParseTuple(args, "nO:nlargest", &n, &iterable)) if (!PyArg_ParseTuple(args, "nO:nlargest", &n, &iterable))
return NULL; return NULL;
...@@ -312,7 +313,12 @@ nlargest(PyObject *self, PyObject *args) ...@@ -312,7 +313,12 @@ nlargest(PyObject *self, PyObject *args)
else else
goto sortit; goto sortit;
} }
if (PyObject_RichCompareBool(elem, sol, Py_LE)) { cmp = PyObject_RichCompareBool(sol, elem, Py_LT);
if (cmp == -1) {
Py_DECREF(elem);
goto fail;
}
if (cmp == 0) {
Py_DECREF(elem); Py_DECREF(elem);
continue; continue;
} }
...@@ -362,12 +368,12 @@ _siftdownmax(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos) ...@@ -362,12 +368,12 @@ _siftdownmax(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
while (pos > startpos){ while (pos > startpos){
parentpos = (pos - 1) >> 1; parentpos = (pos - 1) >> 1;
parent = PyList_GET_ITEM(heap, parentpos); parent = PyList_GET_ITEM(heap, parentpos);
cmp = PyObject_RichCompareBool(newitem, parent, Py_LE); cmp = PyObject_RichCompareBool(parent, newitem, Py_LT);
if (cmp == -1) { if (cmp == -1) {
Py_DECREF(newitem); Py_DECREF(newitem);
return -1; return -1;
} }
if (cmp == 1) if (cmp == 0)
break; break;
Py_INCREF(parent); Py_INCREF(parent);
Py_DECREF(PyList_GET_ITEM(heap, pos)); Py_DECREF(PyList_GET_ITEM(heap, pos));
...@@ -403,14 +409,14 @@ _siftupmax(PyListObject *heap, Py_ssize_t pos) ...@@ -403,14 +409,14 @@ _siftupmax(PyListObject *heap, Py_ssize_t pos)
rightpos = childpos + 1; rightpos = childpos + 1;
if (rightpos < endpos) { if (rightpos < endpos) {
cmp = PyObject_RichCompareBool( cmp = PyObject_RichCompareBool(
PyList_GET_ITEM(heap, childpos),
PyList_GET_ITEM(heap, rightpos), PyList_GET_ITEM(heap, rightpos),
Py_LE); PyList_GET_ITEM(heap, childpos),
Py_LT);
if (cmp == -1) { if (cmp == -1) {
Py_DECREF(newitem); Py_DECREF(newitem);
return -1; return -1;
} }
if (cmp == 1) if (cmp == 0)
childpos = rightpos; childpos = rightpos;
} }
/* Move the smaller child up. */ /* Move the smaller child up. */
...@@ -434,6 +440,7 @@ nsmallest(PyObject *self, PyObject *args) ...@@ -434,6 +440,7 @@ nsmallest(PyObject *self, PyObject *args)
{ {
PyObject *heap=NULL, *elem, *iterable, *los, *it, *oldelem; PyObject *heap=NULL, *elem, *iterable, *los, *it, *oldelem;
Py_ssize_t i, n; Py_ssize_t i, n;
int cmp;
if (!PyArg_ParseTuple(args, "nO:nsmallest", &n, &iterable)) if (!PyArg_ParseTuple(args, "nO:nsmallest", &n, &iterable))
return NULL; return NULL;
...@@ -477,7 +484,12 @@ nsmallest(PyObject *self, PyObject *args) ...@@ -477,7 +484,12 @@ nsmallest(PyObject *self, PyObject *args)
else else
goto sortit; goto sortit;
} }
if (PyObject_RichCompareBool(los, elem, Py_LE)) { cmp = PyObject_RichCompareBool(elem, los, Py_LT);
if (cmp == -1) {
Py_DECREF(elem);
goto fail;
}
if (cmp == 0) {
Py_DECREF(elem); Py_DECREF(elem);
continue; continue;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment