Skip to main content

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: MaxHeap with push/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 (default 10000) — number of items
  • --repeat (default 5) — measured iterations per case
  • --warmup (default 1) — warmup runs
  • --seed (default 1337) — RNG seed
  • --csv — write a results CSV

Benchmarks covered

  • heappush
  • heapify
  • heapify+drain (heapify then pop all)
  • heappushpop
  • heapreplace

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 maxheap is 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 the MaxHeap wrapper 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 (see pyproject.toml)
  • Types: mypy (strict options)
  • Tests: pytest, property tests via hypothesis

PRs and issues welcome!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

maxheapx-0.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl (30.4 kB view details)

Uploaded CPython 3.14tmusllinux: musl 1.2+ x86-64

maxheapx-0.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (30.9 kB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.28+ x86-64manylinux: glibc 2.5+ x86-64

maxheapx-0.1.1-cp314-cp314-musllinux_1_2_x86_64.whl (25.9 kB view details)

Uploaded CPython 3.14musllinux: musl 1.2+ x86-64

maxheapx-0.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (26.1 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.28+ x86-64manylinux: glibc 2.5+ x86-64

maxheapx-0.1.1-cp313-cp313-musllinux_1_2_x86_64.whl (25.8 kB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ x86-64

maxheapx-0.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (26.0 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.28+ x86-64manylinux: glibc 2.5+ x86-64

maxheapx-0.1.1-cp312-cp312-musllinux_1_2_x86_64.whl (25.8 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

maxheapx-0.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (25.9 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ x86-64manylinux: glibc 2.5+ x86-64

maxheapx-0.1.1-cp311-cp311-musllinux_1_2_x86_64.whl (24.8 kB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

maxheapx-0.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (24.8 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ x86-64manylinux: glibc 2.5+ x86-64

maxheapx-0.1.1-cp310-cp310-musllinux_1_2_x86_64.whl (23.4 kB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ x86-64

maxheapx-0.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (23.4 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ x86-64manylinux: glibc 2.5+ x86-64

maxheapx-0.1.1-cp39-cp39-musllinux_1_2_x86_64.whl (23.2 kB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ x86-64

maxheapx-0.1.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (23.2 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.28+ x86-64manylinux: glibc 2.5+ x86-64

File details

Details for the file maxheapx-0.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for maxheapx-0.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 de606dcdadb9898659b136e9d48f3b272b7a357ddc504486e6c5b77845f97548
MD5 2f05d2800a6ea4678df7625e3e534e0e
BLAKE2b-256 8c0e0f719fb5bf642400f7dbdf26753de94ca5c3d46ad039b163346fb9237e75

See more details on using hashes here.

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

File hashes

Hashes for maxheapx-0.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 ff9ea72f8af2a17319892c9c81e560339e4a6bb1b4dc14ea021e657074b508ce
MD5 39f1d43cc7c35f246f56e8ec9fc72773
BLAKE2b-256 2bb975449ede9353cf5bdde5655a82203eece4d5cbd7c48355df8a11a35d2b3c

See more details on using hashes here.

File details

Details for the file maxheapx-0.1.1-cp314-cp314-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for maxheapx-0.1.1-cp314-cp314-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 be3f89d05944cece18175c9db639ee519fc1e8c252561e3c92c0835c81ac2e56
MD5 144b8586d9108870ddf094f286d74ee8
BLAKE2b-256 f26bc1135414b06712f35844c23daab161b6fc89ad3b8df41f4396b4ba2bc22b

See more details on using hashes here.

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

File hashes

Hashes for maxheapx-0.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 abd549dd40421a037bc89c784e6402517c4010f89018252b0dc50522fb8cfe36
MD5 c4e7e9b2d8ad926ae612b39e141c9824
BLAKE2b-256 7ea02b5c4e15e164e6c496561aaa0663854e5174f67af9cee7ea3730f31165fe

See more details on using hashes here.

File details

Details for the file maxheapx-0.1.1-cp313-cp313-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for maxheapx-0.1.1-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 5fa895db83d63bdd56aae86130254f47a83ac235837474082f819b036ee23efe
MD5 adfdc0da2b75d4f1b040547f1a0bb28e
BLAKE2b-256 53f32a610a5b504b1c8c6b8ea5fa85319063cb659a7d34286cab331474b9084d

See more details on using hashes here.

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

File hashes

Hashes for maxheapx-0.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 c909e1492f0f8616d0c753ce519542c43ef46e2204bd95f14c650fabc4838439
MD5 c5e50cc6148ee1d73d1dd23c4d1d3766
BLAKE2b-256 6b6028d187c6e7cdfbc747a62e857f31cab6681ce0194a906f784fa5b1f9dc9d

See more details on using hashes here.

File details

Details for the file maxheapx-0.1.1-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for maxheapx-0.1.1-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 742c4acfb592f9164ca7f4cc780fbe67ed1ca704ee81ca94172de06eb4a73326
MD5 81eecfa00079af69e879c9db1b81a798
BLAKE2b-256 c712a0d96d3290529c49b77d093d35e305ecf94c4b8d1e397798f950957ecbf5

See more details on using hashes here.

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

File hashes

Hashes for maxheapx-0.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 80df0a07193729b9134c04bac958ce7d96a857422ff38821a5a154a1bf9c5ee2
MD5 11a286916e445e7b8153c1d1790c288f
BLAKE2b-256 9c840828b5109013d052e3b716b00392f01b8c8cc4647f5d5f4d1ad4dfaa59f8

See more details on using hashes here.

File details

Details for the file maxheapx-0.1.1-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for maxheapx-0.1.1-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 5c2ab61f5749e96a6566fd644aebd0308faef440948efb7b9af3c605dd58788b
MD5 9214bb3d824ce03765a706fc12d7746d
BLAKE2b-256 a092f6dd0eb50f49e0a73cad8756b15aabbc9161b328856d4a31dcac47f7ee91

See more details on using hashes here.

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

File hashes

Hashes for maxheapx-0.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 574863a484f24d78f7b543de8f50978d99a6f92788261aac9c3a36d2a56c4906
MD5 a8a651f3d6969d1762c12cb5c5313c39
BLAKE2b-256 4c93355b59881e6307e214cbeccf73531ebb0c0b8fe593f614ad1bb92d8c71dc

See more details on using hashes here.

File details

Details for the file maxheapx-0.1.1-cp310-cp310-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for maxheapx-0.1.1-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 476f66e0432e6fb45661a57b22652188c3682506628e79e5227cbd17f98cc6f5
MD5 9711fffc4c9c3c46c10a2e20a643989a
BLAKE2b-256 324bec30a01bc100e119fac77649ec34927a7966891e8fecd68ff75afc6969be

See more details on using hashes here.

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

File hashes

Hashes for maxheapx-0.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 353c19a43c4ba07b9ca88a66d3f792fac82ab91423a1c840e3e53dbf12a00b6b
MD5 623e580128a4545babfb97e51080d27f
BLAKE2b-256 9b14bd8319b78da282e65bc401996465d69cc9f2d58821fa7627f5f08e921d90

See more details on using hashes here.

File details

Details for the file maxheapx-0.1.1-cp39-cp39-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for maxheapx-0.1.1-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 70d3d323edbd8765e50642f035ca5670a16e899c105a77f402ff2e6435c484d0
MD5 90636afb5391be5698b87e8ca0453895
BLAKE2b-256 785b72094cc5a5aba564c508da1904be28de124c70e634928cf1bcf6f73d0709

See more details on using hashes here.

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

File hashes

Hashes for maxheapx-0.1.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 bab208c6a6cb26c61220afc6ee013391d325a362d307218f7ab9f18d285bc69a
MD5 b62f36579b3e350bf58b1092854936bb
BLAKE2b-256 c3b12a7f8496a80578b9c6df20127eaa169552310b14bc6b3379fa2ceb6af3c3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page