P R
P R

Reputation: 1301

Removing tail element of priority queue

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

Answers (8)

user93353
user93353

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

Ilya Gazman
Ilya Gazman

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

Vanji
Vanji

Reputation: 1704

While you add the data into priority queue itself do the comparison;

PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder());

Upvotes: 1

matts
matts

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

T-G
T-G

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

max
max

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

Ehsan
Ehsan

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

user207421
user207421

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

Related Questions