package com.jadekler.sarah;
import java.util.Arrays;
// min-heap
public class HeapSort implements Sort {
private int[] heap;
private int elementCount = 0;
public HeapSort() {
}
public HeapSort(int[] heap, int elementCount) {
this.heap = heap;
this.elementCount = elementCount;
}
public int[] sort(int[] arr) {
heap = new int[arr.length];
elementCount = 0;
for (int i = 0; i < arr.length; i++) {
insert(arr[i]);
}
int[] sortedOutput = new int[arr.length];
for (int i = 0; elementCount > 0; i++) {
sortedOutput[i] = extractMin();
}
return sortedOutput;
}
public int extractMin() {
int root = heap[0];
heap[0] = heap[elementCount-1];
heap[elementCount-1] = 0;
elementCount--;
bubbleDown(0);
return root;
}
public void bubbleDown(int bubbleIndex) {
int leftChildIndex = getLeftChildIndex(bubbleIndex);
int leftOrRightIndex = bubbleIndex;
for (int i = 0; i <= 1; i++) { // left or right
if (leftChildIndex != -1 && leftChildIndex + i < elementCount
&& heap[leftChildIndex + i] < heap[bubbleIndex]) { // this is the important check
if (heap[leftOrRightIndex] > heap[leftChildIndex + i]) {
leftOrRightIndex = leftChildIndex + i; // set to either left or right
}
}
}
if (leftOrRightIndex != bubbleIndex) { // if it got changed, swap
swap(bubbleIndex, leftOrRightIndex);
bubbleDown(leftOrRightIndex);
}
}
private void swap(int a, int b) {
int tmp = heap[a];
heap[a] = heap[b];
heap[b] = tmp;
}
public void insert(int element) {
bubbleUp(element, elementCount);
elementCount++;
}
public void bubbleUp(int element, int bubbleIndex) {
int parentIndex = getParentIndex(bubbleIndex);
if (parentIndex != -1 && heap[parentIndex] > element) {
heap[bubbleIndex] = heap[parentIndex];
heap[parentIndex] = element;
bubbleUp(heap[parentIndex], parentIndex);
} else {
heap[bubbleIndex] = element;
}
}
public int getParent(int childIndex) {
if (childIndex == 0) {
return -1;
}
return heap[getParentIndex(childIndex)];
}
public int getParentIndex(int childIndex) {
if (childIndex == 0) {
return -1;
}
return (childIndex-1) / 2;
}
public int getLeftChildIndex(int parentIndex) {
int childIndex = parentIndex * 2 + 1;
return childIndex > heap.length || childIndex > elementCount ? -1 : parentIndex * 2 + 1;
}
public int[] getHeap() {
return heap;
}
}