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 maxHeapify() takes O(log n) time
* Therefore, buildMaxHeap() 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 MaxHeap {
int[] heap;
int size;
public MaxHeap(int[] heap) {
this.size = heap.length;
this.heap = Arrays.copyOf(heap, size);
}
/**
* Makes the array {@param a} satisfy the max heap property starting from
* {@param index} till the end of array.
* <p/>
* See {@link me.ramswaroop.arrays.sorting.HeapSort#maxHeapify} for a modified
* version of maxHeapify.
* <p/>
* Time complexity: O(log n).
*
* @param index
*/
public void maxHeapify(int index) {
int largest = index;
int leftIndex = 2 * index + 1;
int rightIndex = 2 * index + 2;
if (leftIndex < size && heap[index] < heap[leftIndex]) {
largest = leftIndex;
}
if (rightIndex < size && heap[largest] < heap[rightIndex]) {
largest = rightIndex;
}
if (largest != index) {
swap(index, largest);
maxHeapify(largest);
}
}
/**
* Converts array {@param a} in to a max heap.
* <p/>
* Time complexity: O(n) and is not O(n log n).
*/
public void buildMaxHeap() {
for (int i = size / 2 - 1; i >= 0; i--) {
maxHeapify(i);
}
}
/**
* Insert a new element into the heap satisfying
* the heap property.
*
* Time complexity: O(log n) where 'n' is total no. of
* elements in heap or O(h) where 'h' is the height of
* heap.
*
* @param elem
*/
public void insert(int elem) {
// increase heap size
heap = Arrays.copyOf(heap, size + 1);
int i = size;
int parentIndex = (int) Math.floor((i - 1) / 2);
// move up through the heap till you find the right position
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 findMax() {
if (size == 0) {
return -1;
} else {
return heap[0];
}
}
public int extractMax() {
if (size == 0) return -1;
int min = heap[0];
heap[0] = heap[size - 1];
size--;
maxHeapify(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};
MaxHeap maxHeap = new MaxHeap(a);
maxHeap.printHeap();
maxHeap.buildMaxHeap();
maxHeap.printHeap();
maxHeap.extractMax();
maxHeap.printHeap();
maxHeap.insert(12);
maxHeap.printHeap();
}
}