package com.interview.algorithms.heap;
import java.util.Comparator;
/**
* Created_By: zouzhile
* Date: 10/26/14
* Time: 9:24 AM
*/
public class Heap {
private int capacity = 0;
private int[] buffer;
private int size;
private Comparator<Integer> comparator;
public Heap(int capacity, Comparator<Integer> comparator) {
this.comparator = comparator;
this.capacity = capacity;
this.buffer = new int[this.capacity + 1]; // spare buffer[0]
}
public Heap(int[] buffer, Comparator<Integer> comparator) {
this.comparator = comparator;
this.capacity = buffer.length * 2; // spare buffer[0]
this.size = buffer.length;
this.buffer = new int[capacity + 1];
for(int i = 0; i < buffer.length; i ++)
this.buffer[i+1] = buffer[i]; // buffer[0] is not used
int nonLeafNodeIndex = this.size / 2; // the last
for(int i = nonLeafNodeIndex; i >= 1; i --)
this.swim(i);
}
public void insert(int value) {
if(this.size >= this.capacity) {
this.capacity *= 2;
int[] buffer = new int[this.capacity + 1];
for(int i = 1; i <= this.size; i ++) {
buffer[i] = this.buffer[i];
}
this.buffer = buffer;
}
this.buffer[++size] = value;
this.swim(size/2);
}
public int remove() {
int top = this.buffer[1];
this.buffer[1] = this.buffer[this.size--];
this.sink(1);
return top;
}
public void sink(int index) {
while(index <= this.size/2) { // loop until last non leaf child
// Compare the left and right child
// to see which one should be exchanged with current node
int exchangeChildIndex = 2 * index;
int exchangeChild = this.buffer[2 * index];
if(2 * index + 1 <= this.size) {
if(this.comparator.compare(exchangeChild, this.buffer[2 * index + 1]) < 0) {
exchangeChildIndex = 2 * index + 1;
exchangeChild = this.buffer[exchangeChildIndex];
}
}
if(this.comparator.compare(this.buffer[index], exchangeChild) >= 0) // heap condition met
break;
else {
this.swap(this.buffer, index, exchangeChildIndex);
index = exchangeChildIndex;
}
}
}
public void swim(int index) {
while(index >= 1 && 2 * index <= this.size) { // loop until first node
// Compare the left and right child
// to see which one should be exchanged with current node
int exchangeChildIndex = 2 * index;
int exchangeChild = this.buffer[2 * index];
if(2 * index + 1 <= this.size) {
if(this.comparator.compare(exchangeChild, this.buffer[2 * index + 1]) < 0) {
exchangeChildIndex = 2 * index + 1;
exchangeChild = this.buffer[exchangeChildIndex];
}
}
if(this.comparator.compare(this.buffer[index], exchangeChild) >= 0) // heap condition met
break;
else {
this.swap(this.buffer, index, exchangeChildIndex);
index /= 2;
}
}
}
private void swap(int[] array, int i, int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
public int size() {
return this.size;
}
}