Heap Sort
Problem
Sort the array from small to big with heap sort: first rearrange the array into a max-heap (every parent is not smaller than its children), then repeatedly swap the biggest element (the root) to the end of the unsorted part and repair the heap. Do it in place, in O(n log n). Print the sorted array.
Constraints
- 1 <= n <= 10^5
Examples
Input
5 4 10 3 5 1
Output
1 3 4 5 10
Solutions
Heap sort always takes O(n log n) time and needs no extra array, but it is not stable (equal values can change their order) and it jumps around in memory, so quick sort is often faster in practice.
/*
* Problem : Sorted array.
* Input : n, then n integers.
* Output : The sorted array.
* Approach: Max-heap in place.
* Time : O(n log n)
* Space : O(1)
* Java : 8 or newer.
*/
import java.util.Scanner;
import java.util.Arrays;
import java.util.stream.Collectors;
public class Main {
// Step 1: siftDown moves a value down until both children are not bigger. "size" is the length of the heap part.
static void siftDown(int[] a, int start, int size) {
int index = start;
while (true) {
int left = 2 * index + 1;
int right = left + 1;
int biggest = index;
if (left < size && a[left] > a[biggest]) {
biggest = left;
}
if (right < size && a[right] > a[biggest]) {
biggest = right;
}
if (biggest == index) {
return;
}
int temporary = a[index];
a[index] = a[biggest];
a[biggest] = temporary;
index = biggest;
}
}
// This method solves the task. It receives the input and returns the answer.
static int[] solve(int[] a) {
int[] data = a.clone();
int n = data.length;
// Step 2: Build the max-heap. Leaves are already heaps, so start at the last parent and go back to the root.
for (int i = n / 2 - 1; i >= 0; i--) {
siftDown(data, i, n);
}
// Step 3: Move the biggest value to the end, make the heap one element smaller and repair it.
for (int end = n - 1; end > 0; end--) {
int temporary = data[0];
data[0] = data[end];
data[end] = temporary;
siftDown(data, 0, end);
}
return data;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int size = scanner.nextInt();
int[] a = new int[size];
for (int i = 0; i < size; i++) {
a[i] = scanner.nextInt();
}
System.out.println(Arrays.stream(solve(a)).mapToObj(String::valueOf).collect(Collectors.joining(" ")));
}
}
Hints (1)
- Why do we start building the heap at index n/2 - 1?