I'm trying to implement a heapsort on an array of objects which has already been created. It is meant to be sorted according to their eventTime attribute, yet each eventTime attribute is set to the same as the others by the time the queue is sorted. Is there any way to fix this so that it creates a 'priorityqueue' in ascending order?
Main:
public static void main(String[] args) {
CustomerQueue cQ = new CustomerQueue(0, 0, false);
for (int i = 0; i < 10; i++) {
CustomerQueue cQ1 = new CustomerQueue(0, 0, false);
cQ.enqueue(cQ1);
System.out.println(cQ1.arrivalTime);
}
System.out.print("\n");
PriorityQueue pQ = new PriorityQueue(0, 0, 0, false);
while (!cQ.isEmpty()) {
for (CustomerQueue c : cQ.array) {
PriorityQueue pQ1 = new PriorityQueue(0, 0, 0, false);
pQ1.eventTime = c.arrivalTime;
pQ.enqueue(pQ1);
System.out.println(pQ1.eventTime);
cQ.dequeue();
}
}
pQ.sort(pQ.array);
System.out.println(Arrays.toString(pQ.array));
}
PriorityQueue:
class PriorityQueue {
PriorityQueue array[] = new PriorityQueue[10];
private int front;
private int rear;
private int count;
private int eventType;
double eventTime;
private double tallyTime;
private boolean paymentMethod;
public PriorityQueue(int evT, int eT, double tT, boolean pM) {
this.eventType = evT;
this.eventTime = eT;
this.tallyTime = tT;
this.paymentMethod = pM;
front = 0;
rear = -1;
count = 0;
}
public void enqueue(PriorityQueue pQ) {
if (isFull()) {
System.out.println("OverFlow\nProgram Terminated");
System.exit(1);
}
rear = (rear + 1);
array[rear] = pQ;
count++;
}
public void sort(PriorityQueue arr[]) {
int n = arr.length;
// Build heap (rearrange array)
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
// One by one extract an element from heap
for (int i = n - 1; i >= 0; i--) {
// Move current root to end
int temp = (int) arr[0].eventTime;
arr[0] = arr[i];
arr[i].eventTime = temp;
// call max heapify on the reduced heap
heapify(arr, i, 0);
}
}
void heapify(PriorityQueue arr[], int n, int i) {
int largest = i; // Initialize largest as root
int l = 2 * i + 1; // left = 2*i + 1
int r = 2 * i + 2; // right = 2*i + 2
// If left child is larger than root
if (l < n && arr[l].eventTime > arr[largest].eventTime) {
largest = l;
}
// If right child is larger than largest so far
if (r < n && arr[r].eventTime > arr[largest].eventTime) {
largest = r;
}
// If largest is not root
if (largest != i) {
int swap = (int) arr[i].eventTime;
arr[i] = arr[largest];
arr[largest].eventTime = swap;
// Recursively heapify the affected sub-tree
heapify(arr, n, largest);
}
}
public void dequeue() {
if (isEmpty()) {
System.out.println("UnderFlow\nProgram Terminated");
System.exit(1);
}
front = (front + 1) % array.length;
count--;
}
public boolean isEmpty() {
return (size() == 0);
}
public int size() {
return count;
}
public boolean isFull() {
return (size() == array.length);
}
public PriorityQueue peek() {
if (isEmpty()) {
System.out.println("UnderFlow\nProgram Terminated");
System.exit(1);
}
return array[front];
}
#Override
public String toString() {
return eventType + " " + eventTime + " " + tallyTime + " " + paymentMethod;
}
}
I see two parts which are most likely wrong and the cause of your issue:
In the heapify method you have:
int swap = (int) arr[i].eventTime;
arr[i] = arr[largest];
arr[largest].eventTime = swap;
And in the sort method you have:
int temp = (int) arr[0].eventTime;
arr[0] = arr[i];
arr[i].eventTime = temp;
Assuming you want to switch the CustomerQueue objects around inside the array, they should be this instead:
// In the heapify:
CustomerQueue swap = arr[i];
arr[i] = arr[largest];
arr[largest] = swap;
// In the sort:
CustomerQueue temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
What your code currently does in pseudo-code is this:
CustomerQueue ith has for example name = "I", eventTime = 1
CustomerQueue largest has for example name = "largest", eventTime = 2
int temp = (int) arr[i].eventTime; // temp is now 1
arr[i] = arr[largest]; // Both arr[i] AND arr[largest] are now CustomerQueue largest (with name = "largest" and eventTime = 2)
arr[i].eventTime = temp; // Both arr[i] AND arr[largest] are now changed to eventTime temp (which is 1)
So now both arr[i] and arr[largest] will hold: name = "largest" and eventTime = 1, as well as referencing the same CustomerQueue-instance.
Related
I am trying to build a max heap java class for item objects, so I can solve the knapsack problem and implement greedy algorithms to do so. Item class includes weight, value, Id(to distinguish items), and most importantly a priority factor:
public class Items {
double weight;
double value;
double priorityFactor;
int ID;
//constructor for items class
public Items(int weight, int value, int id, int priorityFactor)
{
this.weight=weight;
this.value=value;
this.ID=id;
this.priorityFactor = priorityFactor;
} //end constructor
Now the issue that I'm facing is in the max heap class, which is supposed to build me a max heap tree based on the priority factor. Means that I should have an array of item objects: private Items[] array
What I'm finding difficult to implement is how can I insert those items in the array based on the priority factor. If I do this, I think I will be able to implement the greedy algorithms. How to handle this?
This is the basic code for a min/max heap (depending on the T:compareTo() method).
This only handles insertion, but I think it's what you're after.
package jc.lib.container.collection.set;
import jc.lib.lang.string.JcStringBuilder;
public class JcHeap<T extends Comparable<T>> {
private T[] mItems;
private int mItemCount = 0;
#SuppressWarnings("unchecked") public JcHeap(final int pStartCapacity) {
mItems = (T[]) new Comparable[pStartCapacity];
}
private void checkResize() {
if (mItems.length <= mItemCount) {
final int newSize = (mItems.length) * 2;
#SuppressWarnings("unchecked") final T[] tmp = (T[]) new Comparable[newSize];
if (mItems != null) System.arraycopy(mItems, 0, tmp, 0, mItemCount);
mItems = tmp;
}
}
static private int getParentIndex(final int pCurrentIndex) {
return (pCurrentIndex - 1) / 2;
}
#SuppressWarnings("unused") static private int getLeftChildIndex(final int pCurrentIndex) {
return 2 * pCurrentIndex + 1;
}
#SuppressWarnings("unused") static private int getRightChildIndex(final int pCurrentIndex) {
return 2 * pCurrentIndex + 2;
}
public void addItem(final T pItem) {
checkResize();
// insert
System.out.println("\nInserting " + pItem);
T current = pItem;
int currentIndex = mItemCount;
mItems[currentIndex] = current;
++mItemCount;
// sort
while (true) { // swap up
if (currentIndex <= 0) break;
final int parentIndex = getParentIndex(currentIndex);
final T parent = mItems[parentIndex];
System.out.print("Checking cur:" + current + " vs par:" + parent + " => " + current.compareTo(parent) + "/");
if (current.compareTo(parent) >= 0) {
System.out.println("break");
break;
}
System.out.println("swap");
System.out.println("Swapping with parent: " + parent);
final T tmp = mItems[parentIndex];
mItems[parentIndex] = mItems[currentIndex];
mItems[currentIndex] = tmp;
currentIndex = parentIndex;
current = mItems[currentIndex];
}
}
// public boolean contains(final T pItem) {
// final int index = findIndex(pItem);
// return 0 <= index && index < mItemCount;
// }
//
// public int findIndex(final T pItem) {
// int index = 0;
// int width = mItemCount;
//
// while (true) {
// System.out.println("Comparing with index " + index);
// final int cmp = pItem.compareTo(mItems[index]);
// if (cmp == 0) return index;
// else if (cmp > 0) return -1;
//
// index += mItemCount;
// width /= 2;
// if (width == 0) return -1;
// }
// }
#Override public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("\nTree View:\n");
int height = (int) (Math.log(mItemCount) / Math.log(2));
sb.append("count=" + mItemCount + " height=" + height);
int next = 1;
sb.append("\n[");
sb.append(JcStringBuilder.buildFromArray(", ", (Object[]) mItems));
// for (int c = 0; c < mItemCount; c++) {
// sb.append("\n" + mItems);
// }
sb.append("]");
for (int c = 0; c < mItemCount; c++) {
if (c + 2 > next) {
sb.append("\n");
for (int d = 0; d < height; d++) {
sb.append("\t");
}
height -= 1;
next *= 2;
// System.out.println("Next is " + next);
}
sb.append("<" + mItems[c] + ">\t");
}
return sb.toString() + "\n";
}
}
I have some problems with my HeapSort implementation. For imstance, I don't know how to fix my IndexOutOfBoundsExcpetion. I have not only the HeapSort class in the file, but also the MinHeap class. Tell me if I should add the part of the other file, where the main method is. I use a counter in order to count the key comparisons. Because I was asked to, I add the main method at the bottom.
public class HeapSort {
int[] heap;
int size;
int count;
public HeapSort(int[] arr, int n, int counter) {
this.heap = arr;
this.size = n;
this.count = counter;
}
public int[] buildHeap(int[] arr) {
int[] build = new int[size];
for (int i = 0; i < size; ++i) {
build[i] = arr[i];
if (!MinHeap.isHeap(build)) {
int[] newBuild = new int[build.length];
newBuild = MinHeap.restoreHeap(i);
build = newBuild;
count();
}
}
return build;
}
//arr is already a Heap
public int[] sort(int[] arr) {
int[] sorted = new int[size];
int val = size;
for (int i = 0; size > 0; ++i) {
int[] newArr = new int[--size];
for (int j = 1; j < size; ++j) newArr[j - 1] = arr[j];
arr = newArr;
sorted[i] = MinHeap.pop();
MinHeap.restoreHeap(0);
count();
}
size = val;
return sorted;
}
public void count() {
++count;
}
#Override
public String toString() {
int arr[] = buildHeap(heap);
int[] array = sort(arr);
String str = "[";
for (int i = 0; i < size - 1; ++i) str += array[i] + ", ";
return str += array[size - 1] + "]";
}
}
class MinHeap {
static int[] heap;
static int size = 0;
public MinHeap() {
heap = new int[size];
}
static int[] restoreHeap(int index) {
// TODO Auto-generated method stub
int v; // current node
int l; // child child
int r; //right child
while (2 * index + 1 < size) {
v = heap[2 * index];
l = heap[2 * index + 1];
if (2 * index + 2 < size) r = heap[2 * index + 2];
else r = 0;
if (compare(l, v) || compare(r, v)) {
//Swap with left child
if (compare(l, r)) {
swap(index, index * 2 + 1);
index = index * 2 + 1;
}
//Swap with right child
else if (compare(r, l)) {
swap(index, index * 2 + 2);
index = index * 2 + 2;
}
}
else break;
}
return heap;
}
static void swap(int v1, int v2) {
int tmp = v1;
v1 = v2;
v2 = tmp;
}
//Remove the first element
static int pop() {
int min = heap[0];
heap[0] = heap[--size];
heap = restoreHeap(0);
return min;
}
static boolean compare(int left, int right) {
return left < right;
}
static boolean isHeap(int[] arr) {
// TODO Auto-generated method stub
int v = 0;
while (2 * v + 1 < size) {
if (2 * v + 2 < size) {
if (arr[v] > arr[2 * v + 1] || arr[v] > arr[2 * v + 2]) return false;
} else if (arr[v] > arr[2 * v + 1]) return false;
v *= 2;
}
return true;
}
static boolean isEmpty() {
return size == 0;
}
}
Main method (in another file):
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; ++i) arr[i] = scanner.nextInt();
int[] sort = sorted.sort(arr);
HeapSort sortHeap = new HeapSort(arr, n, 0);
int[] toSort = sortHeap.buildHeap(arr);
sort = sortHeap.sort(toSort);
int count = sortHeap.count;
if (count != 1) System.out.print("Heap Sort needed " + count + " key
comparisons for sorting the array to: ");
else System.out.print("Heap Sort needed " + count + " key comparison for
sorting the array to: ");
System.out.println(sortHeap.toString());
scanner.close();
}
}
Whats up guys, I have a question regarding the Dijkstra algorithm. I have made it so that a user enter a graph file, and then the user enters the source node and destination node. And my code so far calculates the shortest distance between them, like it's supposed to. However I do not know to print the path of nodes it goes through in order to get to the destination node. Please help this is a homework assignment due today. Here is my code:
package minheap;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class MinHeap {
private int veNum;
private int x;
private int y;
private Vertex[] vertices;
private int size;
public static void main(String[] args) throws FileNotFoundException{
Scanner input = new Scanner(System.in);
System.out.println("%%%%%%Enter the name of the file that contains the graph");
String file = input.nextLine();
MinHeap minHeap = new MinHeap(file);
System.out.println("What city would you like to start from?(Please enter a number "
+ "from 0 to 87574)");
int start = Integer.parseInt(input.nextLine());
System.out.println("What city would you like to get to?(Please enter a number "
+ "from 0 to 87574)");
int end = Integer.parseInt(input.nextLine());
minHeap.findShortestPaths(start, end);
}
public MinHeap(String file) throws FileNotFoundException {
Scanner input = new Scanner(new File(file));
String sizeString = input.next(); //get the size as a string
size = Integer.parseInt(sizeString);
System.out.println("======The size is: " + size);
vertices = new Vertex[size];
// addNodes();
input.next();
/*Now read the vertices*/
for(int i = 0; i < vertices.length; i++){
veNum = Integer.parseInt(input.next());
x = Integer.parseInt(input.next());
y = Integer.parseInt(input.next());
vertices[i] = new Vertex(veNum, x, y);
}
/*Now read the edges */
while(input.hasNext()){
int vertex1 = indexForName(input.next());
int vertex2 = indexForName(input.next());
//System.out.println("====" + vertex1 + "====" + vertex2);
/*Formula to calculate the distance(weight)*/
int distance = (int) Math.sqrt(Math.pow(vertices[vertex1].xCord - vertices[vertex2].xCord, 2)
+ Math.pow(vertices[vertex1].yCord - vertices[vertex2].yCord, 2));
/*Pass the 2 vertexes that make an edge, and their distance to addEdge method*/
addEdge(vertex1, vertex2, distance);
/*System.out.println("X cord: " + vertices[vertex1].xCord + "| Y cord: " + vertices[vertex1].yCord +
"| X cord2: " + vertices[vertex2].xCord + "| Y cord2: " + vertices[vertex2].yCord);
*/
}
}
//======================================================================================================
int indexForName(String name){
for(int i = 0; i < vertices.length; i++){
/*Look for the vertex name in the array to see if they match with the one the one from
the file */
if(vertices[i].name == Integer.parseInt(name)){
return i;
}
}
return -1;
}
//===============================================================================================================
public void addEdge(int sourceName, int destinationName, int weight) {
int srcIndex = sourceName;
int destiIndex = destinationName;
vertices[srcIndex].adj = new Neighbour(destiIndex, weight, vertices[srcIndex].adj);
vertices[destiIndex].indegree++;
}
public void findShortestPaths(int sourceName, int end){
for (int i = 0; i < size; i++) {
if (vertices[i].name == sourceName) {
applyDikjstraAlgorith(vertices[i], vertices[end]);
break;// in this case we need not traverse the nodes which are
// not reachable from the source Node
}
}
//applyDikjstraAlgorith(vertices[sourceName], vertices[end]);
// for(int i = 0; i < size; i++){
// System.out.println("Distance of "+vertices[i].name+" from Source: "+ vertices[i].cost);
//}
}
public class Vertex {
int cost;
int name;
Neighbour adj;
int indegree;
State state;
int xCord;
int yCord;
public Vertex(int name, int xCord, int yCord) {
this.name = name;
cost = Integer.MAX_VALUE;
state = State.NEW;
this.xCord = xCord;
this.yCord = yCord;
}
public int compareTo(Vertex v) {
if (this.cost == v.cost) {
return 0;
}
if (this.cost < v.cost) {
return -1;
}
return 1;
}
}
public enum State {
NEW, IN_Q, VISITED
}
public class Neighbour {
int index;
Neighbour next;
int weight;
Neighbour(int index, int weight, Neighbour next) {
this.index = index;
this.next = next;
this.weight = weight;
}
}
public void applyDikjstraAlgorith(Vertex src, Vertex end) {
Heap heap = new Heap(size);
heap.add(src);
src.state = State.IN_Q;
src.cost = 0;
while (!heap.isEmpty()) {
Vertex u = heap.remove();
u.state = State.VISITED;
Neighbour temp = u.adj; //the neighbor of the vertex being removed. it accesses it adj neighbor list
System.out.println("=======Edge weights");
while (temp != null) { //while it has a neighbor
if (vertices[temp.index].state == State.NEW) { //if that neighbor is unvisited
heap.add(vertices[temp.index]); //add the unvisited vertices to the heap
vertices[temp.index].state = State.IN_Q; //make the state indicating its in the heap
}
System.out.println("Weight from "+ vertices[u.name].name + " to " + vertices[temp.index].name +" is "+ temp.weight);
if (vertices[temp.index].cost > u.cost + temp.weight) { //if the neighbors weight is less than
vertices[temp.index].cost = u.cost + temp.weight;
heap.heapifyUP(vertices[temp.index]);
}
temp = temp.next;
}
}
System.out.println();
System.out.println("The shortest distance from "+src.name +" to "+end.name+" is "
+ end.cost);
}
public static class Heap {
private Vertex[] heap;
private int maxSize;
private int size; //starts off as 0
public Heap(int maxSize) {
this.maxSize = maxSize;
heap = new Vertex[maxSize]; //make the max size for the heap array made of vertices
}
public void add(Vertex u) {
heap[size++] = u; //fill the heap array with the vertices, starting at position 0
//
heapifyUP(size - 1); //pass each vertext ino heapifyUP (vertex type)
}
public void heapifyUP(Vertex u) {
for (int i = 0; i < maxSize; i++) { //look for vertex in the heap array
if (u == heap[i]) {
heapifyUP(i); //if its found, go to heapifyUp method (int type) and pass in the vertex num
break;
}
}
}
public void heapifyUP(int position) {
int currentIndex = position;
Vertex currentItem = heap[currentIndex];
int parentIndex = (currentIndex - 1) / 2;
Vertex parentItem = heap[parentIndex];
while (currentItem.compareTo(parentItem) == -1) {
swap(currentIndex, parentIndex);
currentIndex = parentIndex;
if (currentIndex == 0) {
break;
}
currentItem = heap[currentIndex];
parentIndex = (currentIndex - 1) / 2;
parentItem = heap[parentIndex];
}
}
public Vertex remove() {
Vertex v = heap[0];
swap(0, size - 1);
heap[size - 1] = null;
size--;
heapifyDown(0);
return v;
}
public void heapifyDown(int postion) {
if (size == 1) {
return;
}
int currentIndex = postion;
Vertex currentItem = heap[currentIndex];
int leftChildIndex = 2 * currentIndex + 1;
int rightChildIndex = 2 * currentIndex + 2;
int childIndex;
if (heap[leftChildIndex] == null) {
return;
}
if (heap[rightChildIndex] == null) {
childIndex = leftChildIndex;
} else if (heap[rightChildIndex].compareTo(heap[leftChildIndex]) == -1) {
childIndex = rightChildIndex;
} else {
childIndex = leftChildIndex;
}
Vertex childItem = heap[childIndex];
while (currentItem.compareTo(childItem) == 1) {
swap(currentIndex, childIndex);
currentIndex = childIndex;
currentItem = heap[currentIndex];
leftChildIndex = 2 * currentIndex + 1;
rightChildIndex = 2 * currentIndex + 2;
if (heap[leftChildIndex] == null) {
return;
}
if (heap[rightChildIndex] == null) {
childIndex = leftChildIndex;
} else if (heap[rightChildIndex].compareTo(heap[leftChildIndex]) == -1) {
childIndex = rightChildIndex;
} else {
childIndex = leftChildIndex;
}
}
}
public void swap(int index1, int index2) {
Vertex temp = heap[index1];
heap[index1] = heap[index2];
heap[index2] = temp;
}
public boolean isEmpty() {
return size == 0;
}
}
}
The sample.txt file is as follows:
6 9
0 1000 2400
1 2800 3000
2 2400 2500
3 4000 0
4 4500 3800
5 6000 1500
0 1
0 3
1 2
1 4
2 4
2 3
2 5
3 5
Again, the actual algorithm works, I just need help printing the path. Thanks in advance
I'm using minHeapify structure to extract numbers from an array, and uses this method "minHeapify()" to sort my array, and extractMin() to return the element with the lowest value.
It always return the first element first, and it is having trouble computing negative numbers. This is my code,
public class PQHeap implements PQ {
Element[] eList;
int size;
public PQHeap(int maxElms){
eList= new Element[maxElms];
}
#Override
public Element extractMin() {
size = heapSize(eList);
if (size <= 0) {
System.out.println("Empty Array");
return null;
}
Element min = eList[0];
eList[0] = eList[size -1];
// sets the last index in the array to null
eList[size -1]= null;
size--;
minHeapify(eList, 0);
return min;
}
public void minHeapify(Element[] array, int num){
int l = left(num);
int r = right(num);
int smallest = num;
if (l < size && array[l].key < array[smallest].key){
smallest = l;
}
if (r < size && array[r].key < array[smallest].key){
smallest = r;
}
if (smallest != num){
swap(array, num, smallest);
minHeapify(array, smallest);
}
}
public void swap(Element[] array,int parent, int smallest){
Element tmp= array[parent];
array[parent] = array[smallest];
array[smallest] = tmp;
}
public int heapSize(Element[] array){
size = 0;
for (int i = 0; i <array.length; i++) {
if(array[i] != null){
size++;
}
}
return size;
}
#Override
public void insert(Element e) {
int i = 0;
for (int j = 0; j <eList.length; j++) {
if(eList[i]== null){
eList[i] = e;
break;
}else{
i++;
}
}
}
public int left(int i){
return 2 * i+1;
}
public int right(int i){
return 2 * i + 2;
}
}
The Element array is a must have, so no comments that I should use a arraylist.
When I run the code this is the result:
3,
0,
1,
1,
1,
2,
-117,
3,
5,
100
Here is the testing class:
System.out.println();
System.out.println("Creating a PQHeap with room for 10 elements");
System.out.println();
PQ pq = new PQHeap(10);
System.out.println("Inserting elements with keys");
System.out.println(" 3, 5, 0, 100, -117, 1, 1, 1, 2, 3");
System.out.println("(and corresponding Integers as data)");
System.out.println();
pq.insert(new Element(3,new Integer(3)));
pq.insert(new Element(5,new Integer(5)));
pq.insert(new Element(0,new Integer(0)));
pq.insert(new Element(100,new Integer(100)));
pq.insert(new Element(-117,new Integer(-117)));
pq.insert(new Element(1,new Integer(1)));
pq.insert(new Element(1,new Integer(1)));
pq.insert(new Element(1,new Integer(1)));
pq.insert(new Element(2,new Integer(2)));
pq.insert(new Element(3,new Integer(3)));
System.out.println("Doing 10 extractMins (showing keys and data)");
System.out.println();
Element e;
for (int i=0; i<10; i++){
e = pq.extractMin();
System.out.println(e.key + " " + e.data);
I solved the question, don't know if i should remove post or let it be, but here is the solution. The insert method didn't follow the minHeap structure:
public void insert(Element e) {
size = heapSize(eList);
eList[size] = e;
decreaseKey(eList, size, e.key);
}
public void decreaseKey(Element[] array, int i, int key){
array[i].key = key;
while (i > 0 && array[parent(i)].key > array[i].key){
swap(array,i,parent(i));
i = parent(i);
}
}
I tried to build a minHeap using java, this is my code:
public class MyMinHeap {
private ArrayList<Node> heap;
public MyMinHeap() {
heap = new ArrayList<Node>();
}
public MyMinHeap(ArrayList<Node> nodeList) {
heap = nodeList;
buildHeap();
}
public void buildHeap() {
int i = heap.size() / 2;
while (i >= 0) {
minHeapify(i);
i--;
}
}
public Node extractMin() {
if (heap.size() <= 0) return null;
Node minValue = heap.get(0);
heap.set(0, heap.get(heap.size() - 1));
heap.remove(heap.size() - 1);
minHeapify(0);
return minValue;
}
public String toString() {
String s = "";
for (Node n : heap) {
s += n + ",";
}
return s;
}
public void minHeapify(int i) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int smallest = i;
if (left < heap.size() - 1 && lessThan(left, smallest))
smallest = left;
if (right < heap.size() - 1 && lessThan(right, smallest))
smallest = right;
if (smallest != i) {
swap(smallest, i);
minHeapify(smallest);
}
}
private void swap(int i, int j) {
Node t = heap.get(i);
heap.set(i, heap.get(j));
heap.set(j, t);
}
public boolean lessThan(int i, int j) {
return heap.get(i)
.compareTo(heap.get(j)) < 0;
}
public static void main(String[] args) {
char[] chars = {'a', 'b', 'c', 'd', 'e', 'f'};
int[] freqs = {45, 13, 12, 16, 9, 5};
ArrayList<Node> data = new ArrayList<Node>();
for (int i = 0; i < chars.length; i++) {
data.add(new Node(chars[i], freqs[i]));
}
MyMinHeap heap = new MyMinHeap(data);
System.out.println("print the heap : " + heap);
for (int i = 0; i < chars.length; i++) {
System.out.println("Smallest is :" + heap.extractMin());
}
}
}
The output should be:5,9,12,13,16,45,
but what I got is : 9,13,12,16,45
I have debugged this but still can't figure out, anybody help? thanks a lot.
Insert :
When we insert into a min-heap, we always start by inserting the element at the bottom. We insert at the
rightmost spot so as to maintain the complete tree property.
Then, we "fix" the tree by swapping the new element with its parent, until we find an appropriate spot for
the element. We essentially bubble up the minimum element.
This takes 0 (log n) time, where n is the number of nodes in the heap.
Extract Minimum Element :
Finding the minimum element of a min-heap is easy: it's always at the top. The trickier part is how to remove
it. (I n fact, this isn't that tricky.)
First, we remove the minimum element and swap it with the last element in the heap (the bottommost,
rightmost element). Then, we bubble down this element, swapping it with one of its children until the minheap
property is restored.
Do we swap it with the left child or the right child? That depends on their values. There's no inherent
ordering between the left and right element, but you'll need to take the smaller one in order to maintain
the min-heap ordering.
public class MinHeap {
private int[] heap;
private int size;
private static final int FRONT = 1;
public MinHeap(int maxSize) {
heap = new int[maxSize + 1];
size = 0;
}
private int getParent(int position) {
return position / 2;
}
private int getLeftChild(int position) {
return position * 2;
}
private int getRightChild(int position) {
return position * 2 + 1;
}
private void swap(int position1, int position2) {
int temp = heap[position1];
heap[position1] = heap[position2];
heap[position2] = temp;
}
private boolean isLeaf(int position) {
if (position > size / 2) {
return true;
}
return false;
}
public void insert(int data) {
heap[++size] = data;
int currentItemIndex = size;
while (heap[currentItemIndex] < heap[getParent(currentItemIndex)]) {
swap(currentItemIndex, getParent(currentItemIndex));
currentItemIndex = getParent(currentItemIndex);
}
}
public int delete() {
int item = heap[FRONT];
swap(FRONT, size--); // heap[FRONT] = heap[size--];
heapify(FRONT);
return item;
}
private void heapify(int position) {
if (isLeaf(position)) {
return;
}
if (heap[position] > heap[getLeftChild(position)]
|| heap[position] > heap[getRightChild(position)]) {
// if left is smaller than right
if (heap[getLeftChild(position)] < heap[getRightChild(position)]) {
// swap with left
swap(heap[position], heap[getLeftChild(position)]);
heapify(getLeftChild(position));
} else {
// swap with right
swap(heap[position], heap[getRightChild(position)]);
heapify(getRightChild(position));
}
}
}
#Override
public String toString() {
StringBuilder output = new StringBuilder();
for (int i = 1; i <= size / 2; i++) {
output.append("Parent :" + heap[i]);
output
.append("LeftChild : " + heap[getLeftChild(i)] + " RightChild :" + heap[getRightChild(i)])
.append("\n");
}
return output.toString();
}
public static void main(String... arg) {
System.out.println("The Min Heap is ");
MinHeap minHeap = new MinHeap(15);
minHeap.insert(5);
minHeap.insert(3);
minHeap.insert(17);
minHeap.insert(10);
minHeap.insert(84);
minHeap.insert(19);
minHeap.insert(6);
minHeap.insert(22);
minHeap.insert(9);
System.out.println(minHeap.toString());
System.out.println("The Min val is " + minHeap.delete());
}
}
The problem is in your minHeapify function. You have:
public void minHeapify(int i) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int smallest = i;
if (left < heap.size() - 1 && lessThan(left, smallest))
smallest = left;
if (right < heap.size() - 1 && lessThan(right, smallest))
smallest = right;
Now, let's say that your initial array list is {3,2}, and you call minHeapify(0).
left = 2 * i + 1; // = 1
right = 2 * i + 2; // = 2
smallest = i; // 0
Your next statement:
if (left < heap.size() - 1 && lessThan(left, smallest))
At this point, left = 1, and heap.size() returns 2. So left isn't smaller than heap.size() - 1. So your function exits without swapping the two items.
Remove the - 1 from your conditionals, giving:
if (left < heap.size() && lessThan(left, smallest))
smallest = left;
if (right < heap.size() && lessThan(right, smallest))
smallest = right;