A max-heap library with an API that mirrors Python's heapq (but max-first).
Project description
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!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file maxheapx-0.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 30.4 kB
- Tags: CPython 3.14t, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de606dcdadb9898659b136e9d48f3b272b7a357ddc504486e6c5b77845f97548
|
|
| MD5 |
2f05d2800a6ea4678df7625e3e534e0e
|
|
| BLAKE2b-256 |
8c0e0f719fb5bf642400f7dbdf26753de94ca5c3d46ad039b163346fb9237e75
|
File details
Details for the file maxheapx-0.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 30.9 kB
- Tags: CPython 3.14t, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff9ea72f8af2a17319892c9c81e560339e4a6bb1b4dc14ea021e657074b508ce
|
|
| MD5 |
39f1d43cc7c35f246f56e8ec9fc72773
|
|
| BLAKE2b-256 |
2bb975449ede9353cf5bdde5655a82203eece4d5cbd7c48355df8a11a35d2b3c
|
File details
Details for the file maxheapx-0.1.1-cp314-cp314-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp314-cp314-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 25.9 kB
- Tags: CPython 3.14, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be3f89d05944cece18175c9db639ee519fc1e8c252561e3c92c0835c81ac2e56
|
|
| MD5 |
144b8586d9108870ddf094f286d74ee8
|
|
| BLAKE2b-256 |
f26bc1135414b06712f35844c23daab161b6fc89ad3b8df41f4396b4ba2bc22b
|
File details
Details for the file maxheapx-0.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 26.1 kB
- Tags: CPython 3.14, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
abd549dd40421a037bc89c784e6402517c4010f89018252b0dc50522fb8cfe36
|
|
| MD5 |
c4e7e9b2d8ad926ae612b39e141c9824
|
|
| BLAKE2b-256 |
7ea02b5c4e15e164e6c496561aaa0663854e5174f67af9cee7ea3730f31165fe
|
File details
Details for the file maxheapx-0.1.1-cp313-cp313-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp313-cp313-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 25.8 kB
- Tags: CPython 3.13, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5fa895db83d63bdd56aae86130254f47a83ac235837474082f819b036ee23efe
|
|
| MD5 |
adfdc0da2b75d4f1b040547f1a0bb28e
|
|
| BLAKE2b-256 |
53f32a610a5b504b1c8c6b8ea5fa85319063cb659a7d34286cab331474b9084d
|
File details
Details for the file maxheapx-0.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 26.0 kB
- Tags: CPython 3.13, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c909e1492f0f8616d0c753ce519542c43ef46e2204bd95f14c650fabc4838439
|
|
| MD5 |
c5e50cc6148ee1d73d1dd23c4d1d3766
|
|
| BLAKE2b-256 |
6b6028d187c6e7cdfbc747a62e857f31cab6681ce0194a906f784fa5b1f9dc9d
|
File details
Details for the file maxheapx-0.1.1-cp312-cp312-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp312-cp312-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 25.8 kB
- Tags: CPython 3.12, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
742c4acfb592f9164ca7f4cc780fbe67ed1ca704ee81ca94172de06eb4a73326
|
|
| MD5 |
81eecfa00079af69e879c9db1b81a798
|
|
| BLAKE2b-256 |
c712a0d96d3290529c49b77d093d35e305ecf94c4b8d1e397798f950957ecbf5
|
File details
Details for the file maxheapx-0.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 25.9 kB
- Tags: CPython 3.12, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80df0a07193729b9134c04bac958ce7d96a857422ff38821a5a154a1bf9c5ee2
|
|
| MD5 |
11a286916e445e7b8153c1d1790c288f
|
|
| BLAKE2b-256 |
9c840828b5109013d052e3b716b00392f01b8c8cc4647f5d5f4d1ad4dfaa59f8
|
File details
Details for the file maxheapx-0.1.1-cp311-cp311-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp311-cp311-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 24.8 kB
- Tags: CPython 3.11, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c2ab61f5749e96a6566fd644aebd0308faef440948efb7b9af3c605dd58788b
|
|
| MD5 |
9214bb3d824ce03765a706fc12d7746d
|
|
| BLAKE2b-256 |
a092f6dd0eb50f49e0a73cad8756b15aabbc9161b328856d4a31dcac47f7ee91
|
File details
Details for the file maxheapx-0.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 24.8 kB
- Tags: CPython 3.11, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
574863a484f24d78f7b543de8f50978d99a6f92788261aac9c3a36d2a56c4906
|
|
| MD5 |
a8a651f3d6969d1762c12cb5c5313c39
|
|
| BLAKE2b-256 |
4c93355b59881e6307e214cbeccf73531ebb0c0b8fe593f614ad1bb92d8c71dc
|
File details
Details for the file maxheapx-0.1.1-cp310-cp310-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp310-cp310-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 23.4 kB
- Tags: CPython 3.10, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
476f66e0432e6fb45661a57b22652188c3682506628e79e5227cbd17f98cc6f5
|
|
| MD5 |
9711fffc4c9c3c46c10a2e20a643989a
|
|
| BLAKE2b-256 |
324bec30a01bc100e119fac77649ec34927a7966891e8fecd68ff75afc6969be
|
File details
Details for the file maxheapx-0.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 23.4 kB
- Tags: CPython 3.10, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
353c19a43c4ba07b9ca88a66d3f792fac82ab91423a1c840e3e53dbf12a00b6b
|
|
| MD5 |
623e580128a4545babfb97e51080d27f
|
|
| BLAKE2b-256 |
9b14bd8319b78da282e65bc401996465d69cc9f2d58821fa7627f5f08e921d90
|
File details
Details for the file maxheapx-0.1.1-cp39-cp39-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp39-cp39-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 23.2 kB
- Tags: CPython 3.9, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70d3d323edbd8765e50642f035ca5670a16e899c105a77f402ff2e6435c484d0
|
|
| MD5 |
90636afb5391be5698b87e8ca0453895
|
|
| BLAKE2b-256 |
785b72094cc5a5aba564c508da1904be28de124c70e634928cf1bcf6f73d0709
|
File details
Details for the file maxheapx-0.1.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: maxheapx-0.1.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 23.2 kB
- Tags: CPython 3.9, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bab208c6a6cb26c61220afc6ee013391d325a362d307218f7ab9f18d285bc69a
|
|
| MD5 |
b62f36579b3e350bf58b1092854936bb
|
|
| BLAKE2b-256 |
c3b12a7f8496a80578b9c6df20127eaa169552310b14bc6b3379fa2ceb6af3c3
|