1

I am trying to use the priority queue, but the remove() is not working: My code:

PriorityQueue<OwnClass> pq=new PriorityQueue<OwnClass>();
OwnClass a=new OwnClass(1);
OwnClass b=new OwnClass(2);
OwnClass c=new OwnClass(3);
pq.add(a);
pq.add(b);
pq.add(c);
System.out.println("head:"+pq.peek());
pq.remove(new OwnClass(1));
System.out.println(pq.peek());

And the class implementation:

class OwnClass implements Comparable{

    int x;

    public OwnClass(int x){
        this.x=x;
    }

    public int compareTo(Object arg0) {

        OwnClass a=(OwnClass) arg0;
        if(a.x>this.x)
            return -1;
        if(a.x<x)
            return 1;
        return 0;
    }

    public String toString(){
        return ""+x;        
    }
}

I think the output final output should be 2, since I am removing the added '1'. The compareTo() should be used by priority queue remove() but his does not seem to be the case. What I am doing wrong? I know pq.remove(a) will work, but then my code should also work

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
TimeToCodeTheRoad
  • 7,032
  • 16
  • 57
  • 70
  • You haven't overridden the `equals` method; perhaps that's the problem? – templatetypedef Jan 18 '12 at 07:46
  • but shouldnt the compareTo() method be enough?, as it can be used to check equals – TimeToCodeTheRoad Jan 18 '12 at 07:47
  • 1
    It can and should be used, and by contract when you write a Comparable class, you have to make it so that when compareTo() == 0 then equals() == true. However, a class can violate this contract, normally by accident. In this case OwnClass is violating the contract by not overriding equals; just check what new OwnClass(1).equals(new OwnClass(1)) returns (though compareTo will return 0). – Luis Jan 18 '12 at 07:54

3 Answers3

8

remove() will not use compareTo(), rather it will use equals() to find the object to remove. You need to override equals() on your class as well.

Edit: Javadoc for PriorityQueue (Thanks, @templatetypedef)

sarumont
  • 1,734
  • 12
  • 11
  • 1
    See http://docs.oracle.com/javase/6/docs/api/java/util/PriorityQueue.html#remove(java.lang.Object) for more details – templatetypedef Jan 18 '12 at 07:49
  • ok, i understand, but wy is it implemented in this manner? it does not make sense to code two methods whne only one was enough – TimeToCodeTheRoad Jan 18 '12 at 07:49
  • `remove(Object)` takes an `Object` - it does NOT have to be the same (generic) type of the `PriorityQueue`. Therefore, it cannot be forced into the `Comparable` interface. – sarumont Jan 18 '12 at 08:01
  • I assume the reason it is implemented in this manner is because priority queues can hold multiple, unequal elements that have the same priority. The Priority Queue javadoc states "If multiple elements are tied for least value, the head is one of those elements -- ties are broken arbitrarily" – Kevin Wheeler Dec 24 '14 at 23:39
2

The PriorityQueue class's remove method has the following description:

Removes a single instance of the specified element from this queue, if it is present. More formally, removes an element e such that o.equals(e), if this queue contains one or more such elements. Returns true if and only if this queue contained the specified element (or equivalently, if this queue changed as a result of the call).

Thus compareTo is not used when determining whether to remove something. I believe that this is because PriorityQueue implements Collection, and the behavior of remove must therefore be consistent with the behavior specified in Collection, which is

Removes a single instance of the specified element from this collection, if it is present (optional operation). More formally, removes an element e such that (o==null ? e==null : o.equals(e)), if this collection contains one or more such elements.

In other words, I believe this design decision is motivated by trying to fit PriorityQueue into the Collection framework, even though it is a bit odd.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
2

Please note that PriorityQueue has an other constructor that takes a Comparator. So it could be to keep the remove behavior consistent even if a Comparator is used or the objects in the priorityQueue implement the Comparable Interface, equals does not depend on any comparison except the base equals property of the Object.

NiranjanBhat
  • 1,812
  • 13
  • 17