I have a Point object that just has an x and y, and I have a Heap data structure that looks like so:
class MaxHeap{
public Point[] heap;
public int size;
public int maxsize;
public MaxHeap(int maxsize){
this.maxsize = maxsize;
this.size = 0;
heap = new Point[this.maxsize+1];
heap[0] = new Point(-1,-1); //Heap is empty
}
public int parent(int pos){
return pos /2;
}
public int leftChild(int pos){
return (2 * pos);
}
public int rightChild(int pos){
return (2 * pos) +1;
}
public boolean isLeaf(int pos){
if (pos >= (size / 2) && pos <= size){
return true;
}
return false;
}
public void swap (int fpos, int spos){
Point tmp;
tmp = heap[fpos];
heap[fpos] = heap[spos];
heap[spos] = tmp;
}
public void maxHeapify(int pos){
if (!isLeaf(pos)){
if (heap[pos].getY() < heap[leftChild(pos)].getY() || heap[pos].getY() < heap[rightChild(pos)].getY()){
swap(pos, leftChild(pos));
maxHeapify(leftChild(pos));
}
else{
swap(pos, rightChild(pos));
maxHeapify(rightChild(pos));
}
}
}
public void insert (Point p){
heap[++size] = p;
int current = size;
while (heap[current].getY() > heap[parent(current)].getY()){
swap(current, parent(current));
current = parent(current);
}
}
I am trying to implement a way to remove any Point from the Heap, instead of the traditional remove where it just removes the top. I'm not entirely sure how to go about doing this. I was thinking I could store the index of the Point in the heap inside of the Point. I'm not sure if this would help or not.
Just is case, are you aware that there is standard heap implementation in Java called PriorityQueue? You can use it as the reference of how removeAt(int i) is implemented.
Back to your question.
In order to remove intermediate element from the queue, you need to replace it with the last element of the queue (shrinking the queue by one element) and try to "heapify" this element down. If element is still in place (both children were bigger than the element) you need to "heapify" it up.
Regarding second part of your question. I'd not recommend storing queue indices inside Point class and hence making points queue-aware. The better way is to maintain Map from point to its index inside the queue (this map can be represented by IdentityHashMap[Point, Integer]). Just don't forget to make appropriate changes in this map when you are making changes in the queue, such as inserting, removing elements, swapping them and so on.
this is an anwser :
public void removeSpecificElement(int i) {
heap[i] = heap[size];
size--;
while (getParent(i) < heap[i] && i > 1 ) {
swapElements(heap[i], getParent(i));
i = getParent(i);
}
heapifyUp(i);
}
Related
I've been trying to understand the code given below for a while. This is to implement Queue using array but without counting the elements inside the queue while inserting and deleting i.e. just by using rear and front indexes. Idea behind this was to increment the size of array by 1 so that the conditions for "isFull()" and "isEmpty()" are not the same.
I want to know how adding 1 extra index is solving the problem of differentiating between full and empty. These methods don't make sense to me.
public class QueueWo {
private int maxSize;
private long[] arr;
private int rear;
private int front;
public QueueWo(int s) {
maxSize = s + 1;
arr = new long[maxSize];
rear = -1;
front = 0;
}
public void insert(long j) {
if(rear == maxSize - 1)
rear = -1;
arr[++rear] = j;
}
public long remove() {
long temp = arr[front++];
if(front == maxSize)
front = 0;
return temp;
}
public long peek() {
return arr[front];
}
public boolean isEmpty() {
return rear + 1 == front || front + maxSize - 1 == rear;
}
public boolean isFull() {
return rear + 2 == front || front + maxSize - 2 == rear;
}
public int size() {
if(rear >= front)
return rear - front + 1;
else
return (maxSize - front) + (rear + 1);
}
}
You create a fixed size array and start putting elements in it. Once you reach the end by queuing elements, you start from the start of array and so on in a circular manner. While doing this, your front keeps moving one index ahead on each remove and on reaching the end, starts from the beginning.
I want to shift the elements in the array in a queue style.
I did this code:
public class Queue {
private int[] elements;
private int size;
public static final int DefCap = 8;
public Queue() {
this(DefCap);
}
public Queue(int capacity) {
elements = new int[capacity];
}
public int[] enqueue(int v) {
if (size >= elements.length) {
int[] a = new int[elements.length * 2];
System.arraycopy(elements, 0, a, 0, elements.length);
elements = a;
}
elements[size++] = v;
return elements;
}
public int dequeue() {
return elements[--size];
}
public boolean empty() {
return size == 0;
}
public int getSize() {
return size;
}
}
How can I shift the numbers in the array where the next number added pushes the last one?
because all it does now is removes the last one added (Stacking).
First, remember that it doesn't matter at all how you add or retrieve the elements as long as it appears that the operation reflects that of a queue (i.e. FIFO). The internals of your implementation are of no concern to the user(s). The easiest method (imo) is to add them normally to the end and "remove" them from the beginning.
When you add the new element, do it like you are already doing it.
When you remove the first element, do it virtually by using an index.
int nextIdx = 0; // initialize start of queue
...
...
public int next() {
if (nextIdx < elements.length) {
return elements[nextIdx--];
}
// indicate an error by throwing an exception
}
At some point you are going to want to reclaim the "non-existent" elements at the beginning of the queue and then reset nextIdx. You can do this when you need to resize the array. You can use System.arraycopy and make use of both the value of nextIdx and the new desired new size to resize the array and copy the remaining elements.
Note: In your enqueue method I'm not certain why you want to return the entire element array when you add an element. I would expect something like returning the element just added, a boolean indicating success, or not return anything.
I am trying to create a min heap but I am running into the issue where the numbers that are being displayed in my min heap are all in random order and there are extra 0's where there should be different values. This is the code for my class that does most of the work:
public class Heap211 {
static Random rand = new Random();
static public int[] Heap;
static public int size;
Heap211(){
Heap = new int[30];
size = 0;
}
static public int parent(int index){//location of parent
return index / 2;//array[k / 2]
}
static public int leftChild(int index){//location of left child
return index * 2;//array[k * 2]
}
static public int rightChild(int index){//location of right child
return index * 2 + 1;//array[k * 2 + 1]
}
static public boolean hasParent(int index){
return index > 1;
}
static public boolean hasLeftChild(int index){
return leftChild(index) * 2 <= size;
}
static public boolean hasRightChild(int index){
return rightChild(index * 2) + 1 <= size;
}
static public void swap(int[] a, int index1, int index2){//swaps nodes
int temp = a[index1];
a[index1] = a[index2];
a[index2] = temp;
}
static public int peek(){//peeks at the top of the stack (min value)
return Heap[1];
}
public static boolean isEmpty(){
return size == 0;
}
static int randInt(int min, int max){//generates random int between two numbers
return ((int) (Math.random()*(max - min))) + min;
}
public String toString(){
String result = "[";
if(!isEmpty()){
result += Heap[1];
for(int i = 2; i <= size; i++){
result += ", " + Heap[i];
}
}
return result + "]";
}
public void add(int value){//adds the give value to this priority queue in order
if(size + 1 >= Heap.length){
Heap = Arrays.copyOf(Heap, Heap.length * 2);
}
size++;
Heap[size + 1] = value;//add as rightmost leaf
//"bubble up" as necessary to fix ordering
int index = size + 1;
boolean found = false;
while(!found && hasParent(index) && hasLeftChild(index)){
int parent = parent(index);
if(Heap[index] < Heap[parent]){
swap(Heap, index, parent(index));
index = parent(index);
}else{//after done bubbling up
found = true;
}
}
}
public int remove(){
//move rightmost leaf to become new root
int result = peek();//last leaf -> root
Heap[1] = Heap[size];
size--;
//"bubble down" as necessary to fix ordering
int index = 1;
boolean found = false;
while(!found && hasLeftChild(index)){
int left = leftChild(index);
int right = rightChild(index);
int child = left;
if(hasRightChild(index) && Heap[right] < Heap[left]){
child = right;
}
if(Heap[index] > Heap[child]){
swap(Heap, index, child);
index = child;
}else{
found = true;//found proper location, stop the loop
}
}
return result;
}
This is the code for my main class:
public static void main(String[] args){
Heap211 pq = new Heap211();
for(int node = 1;node <= 30; node++){//loop runs 30 times for 30 nodes
int smValue = randInt(0,2);//generates random number between 1 and 0
if(smValue == 0){//if random number is 0 then it will add random number to heap
int value = randInt(0,100);//generates random number between 0 and 100
System.out.println(node + " Add " + value + ": ");
pq.add(value);//adds random number
System.out.println(pq);//print heap
}else if(smValue == 1 && pq.isEmpty()){
int value = pq.remove();
System.out.println(node + " Remove " + value + ": ");
System.out.println(pq);
}
}
I have a GUI that displays all the numbers but I am getting the wrong output. Any helpful pointers would be greatly appreciated! Thanks.
I found a few problems in your code.
Your hasLeftChild function is wrong. You have return leftChild(index*2) <= size;. But you really should be checking for leftChild(index) <= size. You have a similar error in your hasRightChild function.
Not sure why you pass an array parameter to swap. The only array in which you swap stuff is the Heap array, which is a member of the class.
You have an error in your add method. You increment the size, and then add an item. That is:
size++;
Heap[size + 1] = value;
So imagine what happens when you add the first item. size is equal to 0, and you increment it to 1. Then you add the value at index size+1. So your array contains [0, 0, value]. That's probably the source of your extra 0's. I think what you want is:
Heap[size] = value;
size++;
You'll have to modify the rest of your code to take that into account.
Your "bubble up" loop is kind of wonky. You have:
while (!found && hasParent(index) && hasLeftChild(index))
That's never going to bubble anything up, because when you add something to the last element of the heap, that node doesn't have a left child. You also don't need the found flag. You can write:
while (hasParent(index) && Heap[index] < Heap[parent]]) {
swap(Heap, index, parent(index));
index = parent(index);
}
I can't guarantee that those are the only errors in your code, but they're the ones I found in a quick review of your code.
On a general note, why in the world are you creating a 1-based binary heap in a language that has 0-based arrays? There's no need to do that, and it's confusing as heck. For why I think it's a bad idea, see https://stackoverflow.com/a/49806133/56778 and http://blog.mischel.com/2016/09/19/but-thats-the-way-weve-always-done-it/.
Finally, you should learn to use your debugger, as suggested in comments. Take the time to do it now. It will save you hours of frustration.
I am using array based MinHeap in java. I am trying to create a custom method which can remove any element not only root from the heap but couldn't. Below is MinHeap code-
public class MinHeap {
/** Fixed-size array based heap representation */
private int[] h;
/** Number of nodes in the heap (h) */
private int n = 0;
/** Constructs a heap of specified size */
public MinHeap(final int size) {
h = new int[size];
}
/** Returns (without removing) the smallest (min) element from the heap. */
public int peek() {
if (isEmpty()) {
throw new RuntimeException("Heap is empty!");
}
return h[0];
}
/** Removes and returns the smallest (min) element from the heap. */
public int poll() {
if (isEmpty()) {
throw new RuntimeException("Heap is empty!");
}
final int min = h[0];
h[0] = h[n - 1];
if (--n > 0)
siftDown(0);
return min;
}
/** Checks if the heap is empty. */
public boolean isEmpty() {
return n == 0;
}
/** Adds a new element to the heap and sifts up/down accordingly. */
public void add(final int value) {
if (n == h.length) {
throw new RuntimeException("Heap is full!");
}
h[n] = value;
siftUp(n);
n++;
}
/**
* Sift up to make sure the heap property is not broken. This method is used
* when a new element is added to the heap and we need to make sure that it
* is at the right spot.
*/
private void siftUp(final int index) {
if (index > 0) {
final int parent = (index - 1) / 2;
if (h[parent] > h[index]) {
swap(parent, index);
siftUp(parent);
}
}
}
/**
* Sift down to make sure that the heap property is not broken This method
* is used when removing the min element, and we need to make sure that the
* replacing element is at the right spot.
*/
private void siftDown(int index) {
final int leftChild = 2 * index + 1;
final int rightChild = 2 * index + 2;
// Check if the children are outside the h bounds.
if (rightChild >= n && leftChild >= n)
return;
// Determine the smallest child out of the left and right children.
final int smallestChild = h[rightChild] > h[leftChild] ? leftChild
: rightChild;
if (h[index] > h[smallestChild]) {
swap(smallestChild, index);
siftDown(smallestChild);
}
}
/** Helper method for swapping h elements */
private void swap(int a, int b) {
int temp = h[a];
h[a] = h[b];
h[b] = temp;
}
/** Returns the size of heap. */
public int size() {
return n;
}
}
How can i design a method to remove any element from this MinHeap?
If you know the index of the element to be removed,
private void removeAt(int where) {
// This should never happen, you should ensure to call it only with valid indices
if (n == 0) throw new IllegalArgumentException("Trying to delete from empty heap");
if (where >= n) throw new IllegalArgumentException("Informative error message");
// Now for the working cases
if (where == n-1) {
// removing the final leaf, trivial
--n;
return;
}
// other nodes
// place last leaf into place where deletion occurs
h[where] = h[n-1];
// take note that we have now one element less
--n;
// the new node here can be smaller than the previous,
// so it might be smaller than the parent, therefore sift up
// if that is the case
if (where > 0 && h[where] > h[(where-1)/2]) {
siftUp(where);
} else if (where < n/2) {
// Now, if where has a child, the new value could be larger
// than that of the child, therefore sift down
siftDown(where);
}
}
The exposed function to remove a specified value (if present) would be
public void remove(int value) {
for(int i = 0; i < n; ++i) {
if (h[i] == value) {
removeAt(i);
// assumes that only one value should be removed,
// even if duplicates are in the heap, otherwise
// replace the break with --i to continue removing
break;
}
}
}
Summarising, we can remove a node at a given position by replacing the value with the value of the last leaf (in the cases where the removal is not trivial), and then sifting up or down from the deletion position. (Only one or none sift needs to be done, depending on a comparison with the parent and/or children, if present.)
That works because the heap invariant is satisfied for the parts of the tree above and below the deletion position, so if the new value placed there by the swap is smaller than the parent, sifting up will place it in its proper position above the deletion position. All elements moved are smaller than any element in the children, so the heap invariant is maintained for the part below (and including) the deletion position.
If the new value is larger than one of the direct children, it's basically a removal of the root from the sub-heap topped at the deletion position, so the siftDown restores the heap invariant.
The fix for the mentioned flaw in the siftDown method is to set smallestChild to leftChild if rightChild >= n:
final int smallestChild = (rightChild >= n || h[rightChild] > h[leftChild]) ? leftChild
: rightChild;
// Queue.java
// demonstrates queue
// to run this program: C>java QueueApp
class Queue
{
private int maxSize;
private long[] queArray;
private int front;
private int rear;
private int nItems;
public Queue(int s) // constructor
{
maxSize = s;
queArray = new long[maxSize];
front = 0;
rear = -1;
nItems = 0;
}
public void insert(long j)
{
if(rear == maxSize-1)
rear = -1;
queArray[++rear] = j;
nItems++;
}
public long remove()
{
long temp = queArray[front++];
if(front == maxSize)
front = 0;
nItems--;
return temp;
}
public long peekFront()
{
return queArray[front];
}
public boolean isEmpty() // true if queue is empty
{
return (nItems==0);
}
public boolean isFull() // true if queue is full
{
return (nItems==maxSize);
}
public int size() // number of items in queue
{
return nItems;
}
public void display()
{ int startFront = front;
for (int j = front ;j <nItems; j++ )
{
System.out.println(queArray[j]);
if (j == nItems-1 )
{ j=0;
System.out.println(queArray[j]);
}
if (j==startFront-1)
return;
}
}
}
class QueueApp
{
public static void main(String[] args)
{
Queue theQueue = new Queue(5); // queue holds 5 items
theQueue.insert(10); // insert 4 items
theQueue.insert(20);
theQueue.insert(30);
theQueue.insert(40);
theQueue.remove(); // remove 3 items
theQueue.remove(); // (10, 20, 30)
theQueue.remove();
theQueue.insert(50); // insert 4 more items
theQueue.insert(60); // (wraps around)
theQueue.insert(70);
theQueue.insert(80);
theQueue.display();
while( !theQueue.isEmpty() ) // remove and display
{ // all items
long n = theQueue.remove(); // (40, 50, 60, 70, 80)
System.out.print(n);
System.out.print(" ");
}
System.out.println("");
} // end main()
} // end class QueueApp
Okay, this is the basic, out of the book, queue code. I am attempting to create a display method that will show the queue in order, from front to back. (This is an assignment, i know this is not practical....) If i run the program as is, it will display the queue in order from front to rear(at least that is what i believe i did). The problem i am having is if i change the nItems, it ceases to work. For example if you add the line of code, theQueue.remove(); right above the call to the display, the method ceases to work, i know it is because the front is now = to 4, instead of 3,and it will not enter the for method which needs the front to be < nItems, 4<4 is not true so the for loop does not initiate.
Simply use something like:
public void display() {
for (int i = 0; i < nItems; i++) {
System.out.println(queArray[(front + i) % maxSize]);
}
}
In my opinion you're using too many variables which you don't need. You only need the Queue size and its item count.
public Queue(int s) {
size = s;
queArray = new long[s];
nItems = 0;
}
public void insert(long j) {
if(nItems < size) {
queArray[nItems] = j;
nItems++;
}
}
public long remove() {
if(nItems > 0) {
long temp = queArray[nItems];
nItems--;
return temp;
}
}
public void display() {
for(int j = 0; j < nItems; j++) {
System.out.println(queArray[j]);
}
}
So what's happening right now is that j is the position of the element in your array, which is different from the number of elements that you've printed so far.
You need to either use a different index to count how many elements you printed or check whether you're at the end by comparing j to rear.
When the queue is full (rear == maxSize - 1) and you do a insert, it will replace the first
item, so i think the line nItems++ should not be incremented when the queue is already full.
Edit: Avoid modulus operations when you don't need them, they consume a lot of cpu.
The backing store for your queue is :
private long[] queArray;
Why don't you instead use :
private List<Long> queArray
and let List worry about the resizing effort after add/remove operations. Your current queue implementation needs to know exactly how many elements are going into the queue on construction. That's pretty inconvenient for clients using this API.
You can instantiate the queArray as :
queArray = new ArrayList<Long>();
in your constructor. Once you really understand that code, you can then move onto worrying about the re-sizing logic yourself.