/*
* Author: tdanford
* Date: Nov 15, 2008
*/
package org.seqcode.gseutils.datastructures;
import java.util.*;
/**
* An implementation of a Heap/priority-queue, which is basically derived from the
* pseudocode in:
* "Heapsort", Chapter 6 (pg. 127) of Cormen, Leiserson, Rivest, and Stein (ed. 2)
*
* @author tdanford
*
* @param <Key>
*/
public class Heap<Key extends Comparable> {
public static void main(String[] args) {
Integer[] array = new Integer[] { 5, 15, 23, 1, 2, 6, 21, 99 };
Heap<Integer> heap = new Heap<Integer>(array, -1);
while(heap.size() > 0) {
Integer s = heap.removeFirst();
System.out.print(String.format("%d ", s));
}
System.out.println();
}
private int polarity; // == -1 or 1. polarity == -1 -> min-heap, == 1 -> max-heap
private Vector<KeyWrapper> array;
public Heap(Heap<Key> h) {
array = new Vector<KeyWrapper>(h.array);
polarity = h.polarity;
}
public Heap(Key[] unsorted, int dir) {
array = new Vector<KeyWrapper>();
for(int i = 0; unsorted != null && i < unsorted.length; i++) {
array.add(new KeyWrapper(unsorted[i]));
}
polarity = dir;
if(dir != -1 && dir != 1) { throw new IllegalArgumentException(String.valueOf(dir)); }
for(int i = array.size()/2; i >= 0; i--) {
maxHeapify(i);
}
}
public Heap() {
this(null, 1);
}
public Heap(int dir) {
this(null, dir);
}
public Heap(Key[] unsorted) {
this(unsorted, 1);
}
/*
* Public Methods
*/
public List<Key> asList() {
Heap<Key> h = new Heap<Key>(this);
ArrayList<Key> keys = new ArrayList<Key>();
while(h.size()>0) {
keys.add(h.removeFirst());
}
return keys;
}
public Key getFirst() {
return array.get(0).key;
}
public Key removeFirst() {
if(array.isEmpty()) {
throw new IllegalArgumentException();
}
Key first = array.get(0).key;
int last = array.size()-1;
KeyWrapper w = array.remove(last);
if(!array.isEmpty()) {
array.set(0, w);
maxHeapify(0);
}
return first;
}
public int size() { return array.size(); }
public void insert(Key k) {
KeyWrapper w = new KeyWrapper(-polarity);
array.add(w);
increaseKey(array.size()-1, k);
}
public void increase(Key k1, Key k2) {
for(int i = 0; i < array.size(); i++) {
if(array.get(i).key.equals(k1)) {
increaseKey(i, k2);
return;
}
}
throw new IllegalArgumentException(k1.toString());
}
/*
* Helper Methods
*/
private void increaseKey(int i, Key k) {
KeyWrapper old = array.get(i);
KeyWrapper newWrapper = new KeyWrapper(k);
if(newWrapper.compareTo(old) == -polarity) {
throw new IllegalArgumentException(
String.format("Can't increase/decrease key %s over %s",
newWrapper.key.toString(), old.key.toString()));
}
array.set(i, newWrapper);
while(i > 0 && array.get(parent(i)).compareTo(array.get(i)) == -polarity) {
exchange(i, parent(i));
i = parent(i);
}
}
private int left(int i) {
return i << 1;
}
private int right(int i) {
return (i << 1) + 1;
}
private int parent(int i) {
return i >> 1;
}
private void maxHeapify(int i) {
int l = left(i), r = right(i);
int extreme = i;
if(l < array.size() && array.get(l).compareTo(array.get(i)) == polarity) {
extreme = l;
}
if(r < array.size() && array.get(r).compareTo(array.get(extreme)) == polarity) {
extreme = r;
}
if(extreme != i) {
exchange(extreme, i);
maxHeapify(extreme);
}
}
private void exchange(int i1, int i2) {
KeyWrapper k1 = array.get(i1);
array.set(i1, array.get(i2));
array.set(i2, k1);
}
public static final int MIN = -1;
public static final int MAX = 1;
private class KeyWrapper implements Comparable<KeyWrapper> {
public Key key;
public int special;
public KeyWrapper(Key k) {
key = k;
special = 0;
}
public KeyWrapper(int s) {
key = null;
special = s;
if(special != MIN && special != MAX) {
throw new IllegalArgumentException(String.valueOf(special));
}
}
public boolean equals(Object o) {
if(!(o instanceof Heap.KeyWrapper)) { return false; }
KeyWrapper w = (KeyWrapper)o;
return special == w.special &&
(key == null || w.key == null ? key == w.key : key.equals(w.key));
}
public int hashCode() {
if(key != null) {
return key.hashCode();
} else {
return (17 + special) * 37;
}
}
public int compareTo(KeyWrapper kw) {
if(special == MIN) {
if(kw.special==MIN) {
return 0;
} else {
return -1;
}
} else if (special == MAX) {
if(kw.special==MAX) {
return 0;
} else {
return 1;
}
} else {
if(kw.key != null) {
return key.compareTo(kw.key);
} else {
return -kw.compareTo(this);
}
}
}
}
}