# Weak Heap Sort

# Weak Heap Sort

Weak heap sort is a comparison-based sorting algorithm that improves upon heapsort by reducing the number of comparisons. It uses a structure called a weak heap, where the tree shape is similar to a binary heap but ordering constraints are relaxed and encoded using a bit array.

The algorithm maintains a single root heap and repeatedly extracts the maximum element.

## Problem

Given a sequence $A$ of length $n$, reorder it such that

$$
A[0] \le A[1] \le \cdots \le A[n-1]
$$

## Weak Heap Structure

A weak heap is a binary tree with the following properties:

* Each node may have a left and right child
* The root is the maximum element
* For every node, its value is greater than or equal to all elements in its right subtree
* A bit array encodes whether children are logically swapped

This relaxed condition reduces the number of comparisons during heap construction.

## Key Idea

* Build a weak heap using pairwise joins
* Use a bit array to maintain structural invariants
* Extract the maximum by swapping with the last element
* Restore heap structure efficiently

## Algorithm

```id="k4x9p2"
weak_heap_sort(A):
    n = length(A)
    bits = array of zeros of size n

    for i from n - 1 downto 1:
        j = parent(i)
        while i is a right child:
            i = j
            j = parent(i)

        if A[i] > A[j]:
            swap(A[i], A[j])
            flip bits[i]

    for end from n - 1 downto 1:
        swap(A[0], A[end])
        restore weak heap from root
```

## Example

Let

$$
A = [5, 3, 8, 4, 1]
$$

Build weak heap:

* Pairwise joins enforce ordering constraints

Extract max:

* Move 8 to end
* Restore heap

Repeat:

Final result:

$$
[1, 3, 4, 5, 8]
$$

## Correctness

The weak heap invariant ensures that the root always contains the maximum element. Each join operation maintains the ordering constraint between a node and its descendants. After swapping the root with the last element, restoring the weak heap reestablishes the invariant. Repeating this process extracts elements in decreasing order and produces a sorted sequence.

## Complexity

| phase      |          time |
| ---------- | ------------: |
| build      |        $O(n)$ |
| extraction | $O(n \log n)$ |

Total time:

$$
O(n \log n)
$$

Weak heaps use fewer comparisons than binary heaps, approximately:

$$
n \log n - 0.9n
$$

Space complexity:

$$
O(n)
$$

due to the auxiliary bit array.

## Properties

* not stable
* not strictly in-place due to bit array
* fewer comparisons than heapsort
* more complex structure

## When to Use

Weak heap sort is useful when comparison cost dominates execution time. It is mainly of theoretical and specialized interest. In practice, introsort or heapsort is usually preferred due to simpler implementation.

## Implementation

```id="m2x8q4"
def weak_heap_sort(a):
    n = len(a)
    bits = [0] * n

    def parent(i):
        return (i - 1) // 2

    def join(i, j):
        if a[i] > a[j]:
            a[i], a[j] = a[j], a[i]
            bits[i] ^= 1

    for i in range(n - 1, 0, -1):
        j = parent(i)
        while i % 2 == bits[j]:
            i = j
            j = parent(i)
        join(j, i)

    for end in range(n - 1, 0, -1):
        a[0], a[end] = a[end], a[0]

        i = 0
        while True:
            left = 2 * i + bits[i]
            if left >= end:
                break
            right = left + 1
            if right < end:
                join(left, right)
            join(i, left)
            i = left

    return a
```

```id="z6k3v2"
func WeakHeapSort(a []int) {
    n := len(a)
    bits := make([]int, n)

    parent := func(i int) int {
        return (i - 1) / 2
    }

    join := func(i, j int) {
        if a[i] > a[j] {
            a[i], a[j] = a[j], a[i]
            bits[i] ^= 1
        }
    }

    for i := n - 1; i > 0; i-- {
        j := parent(i)
        for (i%2) == bits[j] {
            i = j
            j = parent(i)
        }
        join(j, i)
    }

    for end := n - 1; end > 0; end-- {
        a[0], a[end] = a[end], a[0]

        i := 0
        for {
            left := 2*i + bits[i]
            if left >= end {
                break
            }
            right := left + 1
            if right < end {
                join(left, right)
            }
            join(i, left)
            i = left
        }
    }
}
```

