package com.interview.graph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Date 04/06/2013
* @author Tushar Roy
*
* Data structure to support following operations
* extracMin - O(logn)
* addToHeap - O(logn)
* containsKey - O(1)
* decreaseKey - O(logn)
* getKeyWeight - O(1)
*
* It is a combination of binary heap and hash map
*
*/
public class BinaryMinHeap<T> {
private List<Node> allNodes = new ArrayList<>();
private Map<T,Integer> nodePosition = new HashMap<>();
public class Node {
int weight;
T key;
}
/**
* Checks where the key exists in heap or not
*/
public boolean containsData(T key){
return nodePosition.containsKey(key);
}
/**
* Add key and its weight to they heap
*/
public void add(int weight,T key) {
Node node = new Node();
node.weight = weight;
node.key = key;
allNodes.add(node);
int size = allNodes.size();
int current = size - 1;
int parentIndex = (current - 1) / 2;
nodePosition.put(node.key, current);
while (parentIndex >= 0) {
Node parentNode = allNodes.get(parentIndex);
Node currentNode = allNodes.get(current);
if (parentNode.weight > currentNode.weight) {
swap(parentNode,currentNode);
updatePositionMap(parentNode.key,currentNode.key,parentIndex,current);
current = parentIndex;
parentIndex = (parentIndex - 1) / 2;
} else {
break;
}
}
}
/**
* Get the heap min without extracting the key
*/
public T min(){
return allNodes.get(0).key;
}
/**
* Checks with heap is empty or not
*/
public boolean empty(){
return allNodes.size() == 0;
}
/**
* Decreases the weight of given key to newWeight
*/
public void decrease(T data, int newWeight){
Integer position = nodePosition.get(data);
allNodes.get(position).weight = newWeight;
int parent = (position -1 )/2;
while(parent >= 0){
if(allNodes.get(parent).weight > allNodes.get(position).weight){
swap(allNodes.get(parent), allNodes.get(position));
updatePositionMap(allNodes.get(parent).key,allNodes.get(position).key,parent,position);
position = parent;
parent = (parent-1)/2;
}else{
break;
}
}
}
/**
* Get the weight of given key
*/
public Integer getWeight(T key) {
Integer position = nodePosition.get(key);
if( position == null ) {
return null;
} else {
return allNodes.get(position).weight;
}
}
/**
* Returns the min node of the heap
*/
public Node extractMinNode() {
int size = allNodes.size() -1;
Node minNode = new Node();
minNode.key = allNodes.get(0).key;
minNode.weight = allNodes.get(0).weight;
int lastNodeWeight = allNodes.get(size).weight;
allNodes.get(0).weight = lastNodeWeight;
allNodes.get(0).key = allNodes.get(size).key;
nodePosition.remove(minNode.key);
nodePosition.remove(allNodes.get(0));
nodePosition.put(allNodes.get(0).key, 0);
allNodes.remove(size);
int currentIndex = 0;
size--;
while(true){
int left = 2*currentIndex + 1;
int right = 2*currentIndex + 2;
if(left > size){
break;
}
if(right > size){
right = left;
}
int smallerIndex = allNodes.get(left).weight <= allNodes.get(right).weight ? left : right;
if(allNodes.get(currentIndex).weight > allNodes.get(smallerIndex).weight){
swap(allNodes.get(currentIndex), allNodes.get(smallerIndex));
updatePositionMap(allNodes.get(currentIndex).key,allNodes.get(smallerIndex).key,currentIndex,smallerIndex);
currentIndex = smallerIndex;
}else{
break;
}
}
return minNode;
}
/**
* Extract min value key from the heap
*/
public T extractMin(){
Node node = extractMinNode();
return node.key;
}
private void printPositionMap(){
System.out.println(nodePosition);
}
private void swap(Node node1,Node node2){
int weight = node1.weight;
T data = node1.key;
node1.key = node2.key;
node1.weight = node2.weight;
node2.key = data;
node2.weight = weight;
}
private void updatePositionMap(T data1, T data2, int pos1, int pos2){
nodePosition.remove(data1);
nodePosition.remove(data2);
nodePosition.put(data1, pos1);
nodePosition.put(data2, pos2);
}
public void printHeap(){
for(Node n : allNodes){
System.out.println(n.weight + " " + n.key);
}
}
public static void main(String args[]){
BinaryMinHeap<String> heap = new BinaryMinHeap<String>();
heap.add(3, "Tushar");
heap.add(4, "Ani");
heap.add(8, "Vijay");
heap.add(10, "Pramila");
heap.add(5, "Roy");
heap.add(6, "NTF");
heap.add(2,"AFR");
heap.decrease("Pramila", 1);
heap.printHeap();
heap.printPositionMap();
}
}