package me.ramswaroop.common;
import java.util.Arrays;
/**
* Created by IntelliJ IDEA.
* <p/>
* A HEAP is a specialized tree-based ABSTRACT DATA TYPE that satisfies the heap property:
* min-heap: All non-leaf elements are either smaller than or equal to their left and right child.
* max-heap: All non-leaf elements are either greater than or equal to their left and right child.
* <p/>
* Often implemented as an array, where the children of the element at index i are at index
* 2i+1 (left child) and 2i+2 (right child).
* <p/>
* The first element (minimum or maximum, depending on chosen order) can be found in O(1).
* Each successor can be found in O(log n). The algorithm in minHeapify() takes O(log n) time
* Therefore, buildMinHeap() would take O(n log n) time BUT IF OBSERVED CAREFULLY IT TAKES 0(N) TIME.
* <p/>
* Used in the HeapSort algorithm. Also can be used to implement a PriorityQueue.
*
* @author: ramswaroop
* @date: 8/2/15
* @time: 11:57 AM
* @see: http://staff.ustc.edu.cn/~csli/graduate/algorithms/book6/chap07.htm
*/
public class MinHeap {
int[] heap;
int size;
public MinHeap(int[] heap) {
this.size = heap.length;
this.heap = Arrays.copyOf(heap, size);
}
/**
* Makes the array {@param a} satisfy the min heap property starting from
* {@param index} till the end of array.
* <p/>
* Time complexity: O(log n).
*
* @param index
*/
public void minHeapify(int index) {
int smallest = index;
int leftIndex = 2 * index + 1;
int rightIndex = 2 * index + 2;
if (leftIndex < size && heap[index] > heap[leftIndex]) {
smallest = leftIndex;
}
if (rightIndex < size && heap[smallest] > heap[rightIndex]) {
smallest = rightIndex;
}
if (smallest != index) {
swap(index, smallest);
minHeapify(smallest);
}
}
/**
* Converts array {@param a} in to a min heap.
* <p/>
* Time complexity: O(n) and is not O(n log n).
*/
public void buildMinHeap() {
for (int i = size / 2 - 1; i >= 0; i--) {
minHeapify(i);
}
}
public void insert(int elem) {
heap = Arrays.copyOf(heap, size + 1);
int i = size;
int parentIndex = (int) Math.floor((i - 1) / 2);
while (i > 0 && elem < heap[parentIndex]) {
heap[i] = heap[parentIndex];
i = parentIndex;
parentIndex = (int) Math.floor((i - 1) / 2);
}
heap[i] = elem;
size++;
}
public int findMin() {
if (size == 0) {
return -1;
} else {
return heap[0];
}
}
public int extractMin() {
if (size == 0) return -1;
int min = heap[0];
heap[0] = heap[size - 1];
size--;
minHeapify(0);
return min;
}
public int getSize() {
return size;
}
public int[] getHeap() {
return heap;
}
public void printHeap() {
if (heap == null)
System.out.print("null");
int iMax = size - 1, i;
if (iMax == -1)
System.out.print("[]");
StringBuilder b = new StringBuilder();
b.append('[');
for (i = 0; i < iMax; i++) {
b.append(heap[i]);
b.append(", ");
}
System.out.println(b.append(heap[i]).append(']').toString());
}
private void swap(int firstIndex, int secondIndex) {
int temp = heap[firstIndex];
heap[firstIndex] = heap[secondIndex];
heap[secondIndex] = temp;
}
// test cases
public static void main(String[] args) {
int[] a = new int[]{2, 4, 5, 1, 6, 7, 8};
MinHeap minHeap = new MinHeap(a);
minHeap.printHeap();
minHeap.buildMinHeap();
minHeap.printHeap();
minHeap.extractMin();
minHeap.printHeap();
minHeap.insert(0);
minHeap.printHeap();
}
}