Powersort

Nearly-optimal run-adaptive stable sorting — now powering Python 3.11+

watch it work

Every array hides a
perfectly balanced tree.

Powersort sorts by merging the runs — already-sorted stretches — that real-world data is full of. To decide which runs to merge first, it assigns each boundary between runs a power: its depth in a virtual, perfectly balanced binary tree laid over the array. Watch it drop into place.

 

1 runs

A single left-to-right scan chops the input into maximal sorted runs (descending runs are reversed on the fly). Nearly-sorted data yields few, long runs — and Powersort gets faster the fewer there are.

2 node powers

Imagine halving the array again and again: the midpoint has power 1, the quarter points power 2, and so on. No tree is ever built — a node's position and depth follow from pure arithmetic on indices.

3 boundary powers

The power of the boundary between two adjacent runs is the depth of the shallowest node lying between their midpoints — computed in a few machine instructions. Low power ⇒ merge late; high power ⇒ merge early.

What is Powersort?

Powersort is a natural run-based mergesort algorithm with provably near-optimal merge cost. It was designed by J. Ian Munro and Sebastian Wild and published at ESA 2018. In Python 3.11, it replaced Timsort's merge policy in CPython, and it is also used beyond CPython (including PyPy and NumPy).

📈

Adaptive to Existing Order

Exploits existing order present in the data, requiring far fewer comparisons on partially-sorted inputs.

Adaptive stable sorting visualization
Different notions of presortedness

Provably Nearly Optimal

Its mathematically grounded node-power merge policy builds merge trees with provable merge cost at most n · H + 2n — sorting with n · H + 3nn log₂ n + O(n) comparisons, where H is the run-length entropy of the input.

Merge tree structure diagram showing node relationships
The order of merges is governed by the merge policy
🐍

Python 3.11 Default

Adopted in CPython 3.11 as a drop-in improvement over Timsort's original merge strategy, with zero API changes for users.

How the Algorithm Works

Like Timsort, Powersort scans the input for natural runs — maximal ascending (or reversed-descending) ranges. The innovation is in how those runs are merged: instead of Timsort's stack-based heuristic, Powersort uses a carefully computed run-boundary power to schedule merges in a near-optimal order.

Detect Natural Runs

Scan left-to-right. A run is a maximal non-decreasing subsequence (descending runs are reversed in-place). If a run is shorter than MIN_RUN (≈ 32–64 elements) it is extended using binary insertion sort.

Compute Node Power

For two adjacent runs A and B in an array of total length n, the node power is computed from their start positions and lengths. Intuitively, it represents the level in a balanced binary tree at which the interval spanned by A ∪ B would first appear.

Maintain a Run Stack

Runs are pushed onto a stack. Before pushing a new run, any pending runs on the stack whose node power is greater than or equal to the new run's power are merged first. This guarantees the merge tree is nearly optimal.

Flush Remaining Runs

After the entire input has been scanned, all remaining runs on the stack are merged right-to-left, completing the sort.

Try it — Powersort in action

Runs are discovered one at a time and kept on a run stack. When a new boundary's power is no larger than the power on top of the stack, the two topmost runs merge — building the merge tree from left to right. Try your own input and watch the policy decide.

Press play to run Powersort.

Note: for clarity this demo uses ascending runs only — real implementations also reverse descending runs (and enforce a minimum run length, see step 1 above).

? why it works

The stack keeps boundary powers strictly increasing from bottom to top, so every merge is a node of the merge tree "closed off" as soon as the scan passes it. Runs are touched only when merged — the whole policy costs O(1) extra work per run.

nearly optimal

The resulting merge tree is within a constant number of comparisons per element of the best possible merge order for those runs — Powersort inherits Timsort's galloping merges but provably avoids its unbalanced-merge worst cases.

🐍 in your Python

Since Python 3.11, CPython's built-in list.sort() and sorted() use Powersort's merge policy — so this exact rule runs billions of times a day.

Run-Boundary Powers

Given an array of length n, two adjacent runs starting at position i and j = i + |A| (where |A| is the length of run A), the run-boundary power k is the number of leading identical bits in the binary representations of the fractions (i + |A|/2) / n and (j + |B|/2) / n. It can be computed as follows (for a more efficient solution, see below):

import math

def power(run1, run2, n):
    i1 = run1[0]; n1 = run1[1]
    i2 = run2[0]; n2 = run2[1]
    assert n1 >= 1 and n2 >= 1
    assert i1 >= 0 and i2 == i1 + n1 and i2 + n2 <= n
    a = (i1 + n1/2) / n
    b = (i2 + n2/2) / n
    l = 0
    while math.floor(a * 2**l) == math.floor(b * 2**l):
        l += 1
    return l

A higher node power means the two runs should be merged sooner (at a deeper level of the merge tree). The stack invariant ensures that merges always happen in the right order.

Comparison with Timsort merge policy

Property Timsort Powersort
Merge policy Ad-hoc heuristic (4 length-based rules) Node-power merge policy
Optimality guarantee ≤ 1.5 · OPT + O(n) merge cost OPT + O(n) merge cost
Worst-case comparisons 1.5 · n log₂ n + O(n) n log₂ n + O(n)
Adaptive to runs Yes (but not optimally) Yes (near-optimal)
Algorithm complexity Complex stack invariants, hard to prove correct Simple, clean invariant
Stable sort Yes Yes
Extra memory O(n) O(n)

🪲 Timsort's troubled merge policy

Part of the reason why Powersort was so welcomed is the troublesome history of Timsort's original merge policy, which has been a source of bugs and confusion in both Python and Java implementations. For many years, the standard library sorting methods were susceptible to a stack overflow from adversarial inputs!

While Timsort was eventually patched, Powersort's mathematically grounded merge policy elegantly resolves this issue from first principles, making the formal proof for correctness and needed stack size robust and intuitive.

Powersort in Python 3.11

Python's built-in list.sort() and sorted() have used Timsort since Python 2.3. With Python 3.11 (released October 2022), the CPython team adopted Powersort's merge strategy, making every Python program that sorts data an implicit beneficiary of this research.

Merged into CPython 3.11

The Powersort merge policy for CPython was integrated via bpo-34561, with the final implementation committed by Tim Peters. It is active in all Python releases from 3.11 onwards. No API changes — list.sort() works exactly as before, just faster and provably better on adversarial inputs.

What changed?

  • The merge-decision logic inside Timsort's run-stacking loop was replaced with the node-power computation — a single integer loop needing no floating-point arithmetic.
  • Timsort's complex merge invariants (stack-balance checks) were simplified while retaining all existing optimisations such as galloping merges and binary insertion sort for short runs.
  • Performance is equivalent or faster across benchmark sets, with measurable wins on adversarial sequences that Timsort handled sub-optimally (see benchmark discussion and bpo-34561).
  • Full backwards compatibility: the sort is still stable, in-place (logically), and respects custom key functions and comparison operators.

Try it yourself

# Python 3.11+ uses Powersort under the hood automatically
import sys
print(sys.version)  # 3.11.x ...

data = [5, 3, 1, 4, 1, 5, 9, 2, 6]
data.sort()       # Powersort at work!
print(data)       # [1, 1, 2, 3, 4, 5, 5, 6, 9]

Implementations & Code

Reference implementations of Powersort are available in several languages, alongside the production-quality CPython implementation. All links below are to open-source code.

Python

PyPy source (listsort.py)

Powersort has also been adapted by Carl Friedrich Bolz-Tereick for PyPy. See the Python source on GitHub in rpython/rlib/listsort.py.

C

CPython 3.11+ (Objects/listobject.c)

The production C source code powering list.sort() in every Python 3.11+ installation. Look for powerloop in the source.

Java

Java implementation

A Java implementation suitable for benchmarking against Java's standard Arrays.sort, also developed by Sebastian Wild as part of the research artefacts for the ESA 2018 paper.

C++

C++ implementation

Low-level C++ implementation repository with variants useful for experiments and direct comparison against other implementations.

C++

NumPy (numpy/_core/src/npysort/timsort.hpp)

NumPy adopted Powersort's merge strategy in its sort implementation. See powerloop and found_new_run_ in the source, introduced via NumPy PR #29208.

Minimal Python sketch

"""
Minimal illustrative Powersort sketch.
For helper functions, see https://tiny.cc/timsort.
"""
import math

def power(run1, run2, n):
    # Compute the "power" of the run boundary.
    # Given are two adjacent runs from a list of total length n.
    # See listsort.txt for details; code follows CPython.
    i1 = run1[0];  n1 = run1[1]
    i2 = run2[0];  n2 = run2[1]
    a = 2 * i1 + n1
    b = a + n1 + n2
    l = 0
    while True:
        l += 1
        if a >= n:
            assert b >= a
            a -= n;  b -= n
        elif b >= n:
            break
        assert a < b < n
        a <<= 1;  b <<= 1
    return l


def powersort(a, extend_run=extend_run):
    """
    Sort a list using powersort.
    This is a slick variant for managing the stack
    (no need to update the power inside the stack).
    It stores the run-boundary power in the right run,
    CPython stores it in the left run.
    """
    n = len(a)
    i = 0
    runs = []  # stack of (start, length, power) tuples
    j = extend_run(a, i)
    runs.append((i, j-i, 0))
    i = j
    while i < n:
        j = extend_run(a, i)
        p = power(runs[-1], (i,j-i), n)
        while p <= runs[-1][2]:
            merge_topmost_2(a, runs)
        runs.append((i,j-i,p))
        i = j
    while len(runs) >= 2:
        merge_topmost_2(a, runs)

Algorithm Variants

The details of Powersort's inner workings make further novel implementation variants possible. A key question is where to put your data; fast stable merging requires a buffer to hold data.

Buffer management and data movement
How to arrange for merging to always have empty space to merge into? Any stable Mergesort has to find a buffer management strategy that balanced extra memory usage, redundant copying, and faster innermost loops.
The interactive animations below let you explore the difference

Publications & Further Reading

The following is a curated list of papers, articles, and resources related to Powersort, and its implementations in various frameworks.

Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs
J. Ian Munro & Sebastian Wild
26th Annual European Symposium on Algorithms (ESA 2018)
Powersort — Wikipedia
Wikipedia — encyclopaedic overview of the Powersort algorithm, its history, and its adoption into Python and NumPy.
listsort.txt — Tim Peters's Description of CPython's List Sort
Tim Peters
CPython source tree — the original detailed description of the Timsort algorithm, including the merge strategy that Powersort later replaced.
Powersort in Python 3.11 (Blog Post)
Sebastian Wild
wild-inter.net — detailed walk-through of the algorithm, its adoption into CPython, and an analysis of the performance improvements.
CPython Issue: Replace Timsort merge strategy with Powersort (bpo-34561)
Sebastian Wild & CPython contributors
bugs.python.org — the original CPython issue tracking the integration of Powersort.
Multiway Powersort
William Cawley Gelling, Markus E. Nebel, Benjamin Smith & Sebastian Wild
Formal description and analysis of a multiway generalisation of Powersort.
PyCon US 2023 Talk: Powersort
Sebastian Wild
PyCon US 2023 — talk introducing Powersort and its adoption into CPython.
The Powersort Game
Tony McCabe
Interactive game to test how well you can find good merge policies.
Powersort Competition
University of Liverpool
Competition website for the Powersort algorithm challenge, sponsored by the University of Liverpool.
An Interactive Explanation of Powersort (Blog Post)
Moritz Groß
moritz-gross.github.io — interactive walk-through of the Powersort algorithm with manipulatable animations that let readers explore the merge strategy step by step.

On this page, I collect basic information and links about Powersort. I've been doing this on my personal website, but felt it's time to move it to a dedicated site to make it easier to find and explore, and let other contribute to it.

Contact: Questions or contributions? Email powersort@liverpool.ac.uk or open an issue on the powersort GitHub organisation ↗.