maxheap
A max-heap library with an API that mirrors Python’s heapq—but max-first.
It ships with a fast C accelerator (maxheap._cmaxheap) and a pure-Python fallback.
- Python: 3.9–3.13
- License: MIT
- Package name:
maxheap
Features
- Functional API:
heapify,heappush,heappop,heappushpop,heapreplace,peek,is_heap - OO wrapper:
MaxHeapwithpush/pop/peek/replace/pushpop - Optional C extension for speed; pure-Python fallback if unavailable
- Reproducible microbenchmarks with CSV output
- Test suite (
pytest) including property tests
Quickstart (from a fresh clone)
Run all commands from the project root (the folder that contains
pyproject.toml).
macOS/Linux (bash/zsh)
# 0) Verify you're in the repo root
pwd
ls pyproject.toml
# 1) Create a clean virtualenv
python3 -m venv .venv
# 2) Activate it
source .venv/bin/activate
# 3) Confirm it's active & valid
echo "VIRTUAL_ENV=$VIRTUAL_ENV"
test -x .venv/bin/python && echo "venv OK" || echo "venv MISSING"
python -V
# 4) Install in editable mode (builds the C extension)
python -m pip install -U pip setuptools wheel
python -m pip install -e .
# 5) Sanity check the extension is loaded
python - <<'PY'
import maxheap, sys
print("HAVE_CEXT:", getattr(maxheap, "_HAVE_CEXT", None))
print("heapify impl:", maxheap.heapify.__module__)
print("python:", sys.version)
PY
Expected:
HAVE_CEXT: True
heapify impl: maxheap._cmaxheap
python: 3.13.x (...)
If HAVE_CEXT is False, you’re using the pure-Python fallback.
Windows (PowerShell)
# 0) Verify you're in the repo root
Get-ChildItem pyproject.toml
# 1) Create a venv
py -m venv .venv
# 2) Activate
. .\.venv\Scripts\Activate.ps1
# 3) Install (use -m to ensure the venv's Python)
python -m pip install -U pip setuptools wheel
python -m pip install -e .
# 4) Sanity
python - <<'PY'
import maxheap, sys
print("HAVE_CEXT:", getattr(maxheap, "_HAVE_CEXT", None))
print("heapify impl:", maxheap.heapify.__module__)
print("python:", sys.version)
PY
Rebuilding after C changes
Any time you modify src/maxheap/_cmaxheap.c, rebuild:
# inside the activated venv
rm -rf build
python -m pip install -e .
Usage
The API mirrors Python’s built-in heapq — but instead of a min-heap that requires negating keys for max-first behavior, maxheap stores the largest element at index 0 and operates directly without the negation overhead.
You can choose between a functional API (works on plain lists) and an OO wrapper (MaxHeap class).
Functional API
import maxheap as heapq # same API names as heapq
# Start with an empty list
h = []
# Push elements
heapq.heappush(h, 3)
heapq.heappush(h, 10)
heapq.heappush(h, 5)
# Peek at the largest without removing it
heapq.peek(h) # -> 10
# Pop the largest
heapq.heappop(h) # -> 10
heapq.peek(h) # -> 5
# Replace the largest atomically
heapq.heapreplace(h, 4) # pops max (5), pushes 4 -> returns 5
# Push an element and pop the largest in a single step
heapq.heappushpop(h, 7) # pushes 7, pops max -> returns 7
# Turn any list into a valid max-heap in place
data = [1, 8, 3, 2]
heapq.heapify(data) # data is now a valid max-heap
When to use:
- You want to use the
heapq-style API but without the min-heap + negation hack. - You don’t need to subclass or wrap the heap in your own object.
OO wrapper
from maxheap import MaxHeap
# Initialize from iterable
h = MaxHeap([3, 1, 6, 5, 2, 4])
# Push and pop
h.push(10)
h.peek() # -> 10
h.pop() # -> 10
# Length and iteration
len(h) # -> 6
list(h) # Pops all items in descending order
# Check if a list is a valid max-heap
MaxHeap.is_heap([10, 5, 6, 2]) # True
When to use:
- You want an object that owns its heap data.
- You want utility methods (
peek,is_heap, iteration) with clean semantics.
Tip: All hot-path operations (heapify, heappush, heappop, heappushpop, heapreplace) are C-accelerated — so you get max-heap behavior faster than heapq with negation.
Running the tests
# ensure venv is active and package is installed
source .venv/bin/activate # Windows: .venv\Scripts\activate
python -m pip install -e .
python -m pip install -q pytest hypothesis
python -m pytest -q
You should see all tests green (tests/test_maxheap.py, tests/test_properties.py).
Benchmarks
The benchmark compares maxheap with a baseline using stdlib heapq as a max-heap via negation (-x).
Quick run
python benchmarks/bench_maxheap.py
Larger run + CSV output
mkdir -p benchmarks
python benchmarks/bench_maxheap.py --n 100000 --repeat 10 --warmup 3 --seed 1 \
--csv benchmarks/results.csv
head benchmarks/results.csv
CLI flags
--n(default10000) — number of items--repeat(default5) — measured iterations per case--warmup(default1) — warmup runs--seed(default1337) — RNG seed--csv— write a results CSV
Benchmarks covered
heappushheapifyheapify+drain(heapify then pop all)heappushpopheapreplace
Interpreting output
Each line prints min / median / mean. When a baseline exists (the negation variant), a % indicates median speedup (positive = faster than baseline).
A/B: Force the pure-Python fallback (optional)
If you want to compare C vs Python on your machine, temporarily let the package respect an env var:
# top of src/maxheap/__init__.py
import os
try:
if os.getenv("MAXHEAP_PURE"):
raise ImportError
from ._cmaxheap import heapify, heappush, heappop, heappushpop, heapreplace # type: ignore
_HAVE_CEXT = True
except Exception:
from ._core import heapify, heappush, heappop, heappushpop, heapreplace
_HAVE_CEXT = False
Then:
python -m pip install -e .
python benchmarks/bench_maxheap.py --csv benchmarks/results_cext.csv
MAXHEAP_PURE=1 python benchmarks/bench_maxheap.py --csv benchmarks/results_pure.csv
Packaging (optional)
rm -rf dist
python -m build # pip install build, if needed
python -m pip install -U twine
twine upload --repository testpypi dist/*
Fresh-venv verification:
python -m venv /tmp/venv && source /tmp/venv/bin/activate
python -m pip install -i https://test.pypi.org/simple/ maxheap
python - <<'PY'
import maxheap
print(maxheap._HAVE_CEXT, maxheap.heapify.__module__)
PY
Project layout
.
├── benchmarks/
│ └── bench_maxheap.py # microbenchmarks (CSV capable)
├── src/
│ └── maxheap/
│ ├── _cmaxheap.c # C accelerator (optional)
│ ├── _core.py # pure-Python implementation
│ └── __init__.py # optional import of C ext, fallback to Python
├── tests/
│ ├── test_maxheap.py # unit tests
│ └── test_properties.py # property-based tests
├── pyproject.toml
└── README.md
Troubleshooting
“.venv/bin/python: No such file or directory” or prompt shows (.venv) but it’s broken
You’re in a shell with a stale venv path. Fix:
deactivate 2>/dev/null || true
rm -rf .venv build *.egg-info src/*.egg-info
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip setuptools wheel
python -m pip install -e .
Check:
echo "$VIRTUAL_ENV" # should point to .../maxheap/library/.venv
which python # should be .../maxheap/library/.venv/bin/python
“ModuleNotFoundError: No module named 'maxheap'”
-
Ensure you ran
python -m pip install -e .in the repo root. -
Ensure tests are run with the same venv:
python -m pytest -q
-
Confirm where
maxheapis imported from:python - <<'PY'
import maxheap, os print(os.path.dirname(maxheap.file)) PY
### Rebuild didn’t pick up code changes
Remove build artifacts and reinstall:
```bash
rm -rf build
python -m pip install -e .
API reference (quick)
# functional API
heapify(x: List[T]) -> None
heappush(heap: List[T], item: T) -> None
heappop(heap: List[T]) -> T
heappushpop(heap: List[T], item: T) -> T
heapreplace(heap: List[T], item: T) -> T
peek(heap: List[T]) -> T
is_heap(x: List[T]) -> bool
# OO wrapper
class MaxHeap(Generic[T]):
def __init__(self, iterable: Optional[Iterable[T]] = None) -> None: ...
def push(self, item: T) -> None: ...
def pop(self) -> T: ...
def peek(self) -> T: ...
def replace(self, item: T) -> T: ...
def pushpop(self, item: T) -> T: ...
def heap(self) -> List[T]: ...
def __len__(self) -> int: ...
Notes on performance
- The accelerator focuses on the hot operations that do comparisons and pointer moves (
heapify,heappush,heappop,heappushpop,heapreplace). peek,is_heap, and theMaxHeapwrapper remain in Python—these aren’t hot in typical workloads, and keeping them in Python preserves readability.
Benchmark highlights
| operation | median time (s) | speedup vs heapq+negation |
|---|---|---|
| heappush (maxheap) | 0.00535 | ~19% faster |
| heapify (maxheap) | 0.00349 | ~28% faster |
| heapify+drain (maxheap) | 0.04043 | ~41% faster |
Result: Max-first heap without the negation hack, and still beating the pants off heapq.
Contributing
- Format/lint:
ruff(seepyproject.toml) - Types:
mypy(strict options) - Tests:
pytest, property tests viahypothesis
PRs and issues welcome!
Metadata
Release files for maxheapx 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
Total release size: 359.5 kB
Release files / maxheapx-0.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl
| Download URL | maxheapx-0.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 30.4 kB |
| Tags | CPython 3.14 CPython 3.14 free-threading Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
de606dcdadb9898659b136e9d48f3b272b7a357ddc504486e6c5b77845f97548
|
|
BLAKE2b-256 checksum How to use checksums |
8c0e0f719fb5bf642400f7dbdf26753de94ca5c3d46ad039b163346fb9237e75
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | maxheapx-0.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 30.9 kB |
| Tags | CPython 3.14 CPython 3.14 free-threading Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
ff9ea72f8af2a17319892c9c81e560339e4a6bb1b4dc14ea021e657074b508ce
|
|
BLAKE2b-256 checksum How to use checksums |
2bb975449ede9353cf5bdde5655a82203eece4d5cbd7c48355df8a11a35d2b3c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp314-cp314-musllinux_1_2_x86_64.whl
| Download URL | maxheapx-0.1.1-cp314-cp314-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 25.9 kB |
| Tags | CPython 3.14 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
be3f89d05944cece18175c9db639ee519fc1e8c252561e3c92c0835c81ac2e56
|
|
BLAKE2b-256 checksum How to use checksums |
f26bc1135414b06712f35844c23daab161b6fc89ad3b8df41f4396b4ba2bc22b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | maxheapx-0.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 26.1 kB |
| Tags | CPython 3.14 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
abd549dd40421a037bc89c784e6402517c4010f89018252b0dc50522fb8cfe36
|
|
BLAKE2b-256 checksum How to use checksums |
7ea02b5c4e15e164e6c496561aaa0663854e5174f67af9cee7ea3730f31165fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp313-cp313-musllinux_1_2_x86_64.whl
| Download URL | maxheapx-0.1.1-cp313-cp313-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 25.8 kB |
| Tags | CPython 3.13 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
5fa895db83d63bdd56aae86130254f47a83ac235837474082f819b036ee23efe
|
|
BLAKE2b-256 checksum How to use checksums |
53f32a610a5b504b1c8c6b8ea5fa85319063cb659a7d34286cab331474b9084d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | maxheapx-0.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 26.0 kB |
| Tags | CPython 3.13 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
c909e1492f0f8616d0c753ce519542c43ef46e2204bd95f14c650fabc4838439
|
|
BLAKE2b-256 checksum How to use checksums |
6b6028d187c6e7cdfbc747a62e857f31cab6681ce0194a906f784fa5b1f9dc9d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp312-cp312-musllinux_1_2_x86_64.whl
| Download URL | maxheapx-0.1.1-cp312-cp312-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 25.8 kB |
| Tags | CPython 3.12 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
742c4acfb592f9164ca7f4cc780fbe67ed1ca704ee81ca94172de06eb4a73326
|
|
BLAKE2b-256 checksum How to use checksums |
c712a0d96d3290529c49b77d093d35e305ecf94c4b8d1e397798f950957ecbf5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | maxheapx-0.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 25.9 kB |
| Tags | CPython 3.12 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
80df0a07193729b9134c04bac958ce7d96a857422ff38821a5a154a1bf9c5ee2
|
|
BLAKE2b-256 checksum How to use checksums |
9c840828b5109013d052e3b716b00392f01b8c8cc4647f5d5f4d1ad4dfaa59f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp311-cp311-musllinux_1_2_x86_64.whl
| Download URL | maxheapx-0.1.1-cp311-cp311-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 24.8 kB |
| Tags | CPython 3.11 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
5c2ab61f5749e96a6566fd644aebd0308faef440948efb7b9af3c605dd58788b
|
|
BLAKE2b-256 checksum How to use checksums |
a092f6dd0eb50f49e0a73cad8756b15aabbc9161b328856d4a31dcac47f7ee91
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | maxheapx-0.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 24.8 kB |
| Tags | CPython 3.11 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
574863a484f24d78f7b543de8f50978d99a6f92788261aac9c3a36d2a56c4906
|
|
BLAKE2b-256 checksum How to use checksums |
4c93355b59881e6307e214cbeccf73531ebb0c0b8fe593f614ad1bb92d8c71dc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp310-cp310-musllinux_1_2_x86_64.whl
| Download URL | maxheapx-0.1.1-cp310-cp310-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 23.4 kB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
476f66e0432e6fb45661a57b22652188c3682506628e79e5227cbd17f98cc6f5
|
|
BLAKE2b-256 checksum How to use checksums |
324bec30a01bc100e119fac77649ec34927a7966891e8fecd68ff75afc6969be
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | maxheapx-0.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 23.4 kB |
| Tags | CPython 3.10 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
353c19a43c4ba07b9ca88a66d3f792fac82ab91423a1c840e3e53dbf12a00b6b
|
|
BLAKE2b-256 checksum How to use checksums |
9b14bd8319b78da282e65bc401996465d69cc9f2d58821fa7627f5f08e921d90
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp39-cp39-musllinux_1_2_x86_64.whl
| Download URL | maxheapx-0.1.1-cp39-cp39-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 23.2 kB |
| Tags | CPython 3.9 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
70d3d323edbd8765e50642f035ca5670a16e899c105a77f402ff2e6435c484d0
|
|
BLAKE2b-256 checksum How to use checksums |
785b72094cc5a5aba564c508da1904be28de124c70e634928cf1bcf6f73d0709
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / maxheapx-0.1.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | maxheapx-0.1.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 23.2 kB |
| Tags | CPython 3.9 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
bab208c6a6cb26c61220afc6ee013391d325a362d307218f7ab9f18d285bc69a
|
|
BLAKE2b-256 checksum How to use checksums |
c3b12a7f8496a80578b9c6df20127eaa169552310b14bc6b3379fa2ceb6af3c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|