Reputation: 1301
How can I remove the tail element of a priority queue? I am trying to implement beam search using a priority queue and once the priority queue is full, I want to remove the last element(the element with the least priority).
Thanks!
Upvotes: 10
Views: 37614
Reputation: 14039
No easy way. Copy elements from original to new except the last.
PriorityQueue removelast(PriorityQueue pq)
{
PriorityQueue pqnew = new PriorityQueue();
while(pq.size() > 1)
{
pqnew.add(pq.poll());
}
pq.clear();
return pqnew;
}
called as
pq = removelast(pq);
Upvotes: 6
Reputation: 32211
Removing the tail is not supported.
The best thing you can do is to swap the order of elements so that the tail becomes head, and remove()
it instead.
Upvotes: 0
Reputation: 1704
While you add the data into priority queue itself do the comparison;
PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder());
Upvotes: 1
Reputation: 6887
You could probably use Guava's MinMaxPriorityQueue to do this. It provides peek, poll, and remove methods for both ends of the queue.
Another option is to write a Queue wrapper that enforces bounding, similar to this answer. You'd need to implement offer
, add
, and addAll
to check capacity. Something like:
public class BoundedQueue<E> implements Serializable, Iterable<E>, Collection<E>, Queue<E> {
private final Queue<E> queue;
private int capacity;
public BoundedQueue(Queue<E> queue, int capacity) {
this.queue = queue;
this.capacity = capacity;
}
@Override
public boolean offer(E o) {
if (queue.size() >= capacity)
return false;
return queue.add(o);
}
@Override
public boolean add(E o) throws IllegalStateException {
if (queue.size() >= capacity)
throw new IllegalStateException("Queue full"); // same behavior as java.util.ArrayBlockingQueue
return queue.add(o);
}
@Override
public boolean addAll(Collection<? extends E> c) {
boolean changed = false;
for (E o: c)
changed |= add(o);
return changed;
}
// All other methods simply delegate to 'queue'
}
Upvotes: 6
Reputation: 1
There is a better solution in case you have a reason not to generate another element to the memory.
you can get the size of the Queue and run over it with an iterator while counting the elements you are going over, once you get to the last one OR the one you are looking for, you can use PriorityQueue.remove(Object o)
Iterator<E> it = Queue.iterator();
while (it.hasNext()) {
temp<E> = it.next();
counter++;
if (counter == Queue.size()) {
Queue.remove(temp);
}
}
Upvotes: 0
Reputation: 791
I think, PR's use case is, that he needs the head, but also want to have a small PQ, so the idea is to remove the tail.
As a PQ is realized as a binary tree mapped to an array, the head is always the first element of the backing array (queue[0]
), but the tail is not always at the end of the array, you had to search it.
I think a nice way is to subclass PQ and write the following two methods:
public class MyPriorityQueue<E> extends PriorityQueue<E>
{
// constructors
public E getTail()
{
// queue.length can be bigger than this.size() !!
Object[] queue = this.toArray();
E tail = (E)queue[0];
Comparator<? super E> comparator = this.comparator();
if (comparator !=null)
for(int i = 1; i < this.size(); i++)
if ( comparator.compare(tail, (E)queue[i]) < 0)
tail = (E)queue[i];
else
for(int j = 1; j < this.size(); j++)
if ( ((Comparable)tail).compareTo( ((Comparable)queue[j]) ) < 0 )
tail = (E)queue[j];
return tail;
}
public E removeTail()
{
E tail = this.getTail();
this.remove(tail);
return tail;
}
}
Upvotes: 2
Reputation: 92
If you are concerned with the runtime, I suggest implementing your own queue. I did the following and worked in my project.
1) copy paste the code from PriorityQueue -> CustomQueue.java 2) Add a method removeLast() 3) This is the implementation I used (very minimal)
public void removeLast() {
if(size == 0) {
return;
}
queue[size - 1] = null;
size--;
}
The reason this works is that the implementation of PriorityQueue uses an array to hold object. So "size" is infact a pointer to the next available spot in the array. By reducing it, the size of the array/queue is reduced, as if you are dropping the last element.
Upvotes: -3
Reputation: 310866
Use an inverting Comparator and remove from the head. If you need both the head and the tail you are using the wrong data structure.
Upvotes: 7