Niko H
Niko H

Reputation: 63

Why can't I add on PriorityQueue?

I'm having troubles adding an Object Node to my PriorityQueue and I cant figure out why. When I add Node a, it has no problem.

PriorityQueue<Node> q = new PriorityQueue<Node>();
Node a = new Node('a', 1);

q.add(a);

but if I add a second Node, it throws an exception saying "java.lang.ClassCastException: Node cannot be cast to java.lang.Comparable"

PriorityQueue<Node> q = new PriorityQueue<Node>();
Node a = new Node('a', 1);
Node b = new Node('b', 2);

q.add(a);
q.add(b);

My Node class is below:

public class Node {
    public int count;
    public char character;
    public Node left;
    public Node right;

    public Node(char character, int count) {
        this(character, count, null, null);
    }

    public Node(char character, int count, Node left, Node right) {
        this.count = count;
        this.character = character;
        this.left = left;
        this.right = right;
    }

    public int compareTo(Node other) {
        return this.count - other.count;
    }
}

I guess I'm just confused why it can add Node a but not add Node b. I looked up what ClassCastException is and I dont really see that I did that kind of exception since I'm adding a type Node to a PriorityQueue of type Nodes. I would appreciate any help. Thank you!

Upvotes: 1

Views: 697

Answers (5)

Sync it
Sync it

Reputation: 1198

Node should inherit Comparable as follows:

public class Node implements Comparable<Node> {
    ...

    @Override
    public int compareTo(Node n) {
        ...
    }
}

Upvotes: 1

Tom
Tom

Reputation: 765

implements Comparable<Node> is missing in your class Node:

public class Node implements Comparable<Node> {
    public int count;
    public char character;
    public Node left;
    public Node right;

    public Node(char character, int count) {
        this(character, count, null, null);
    }

    public Node(char character, int count, Node left, Node right) {
        this.count = count;
        this.character = character;
        this.left = left;
        this.right = right;
    }

    @Override
    public int compareTo(Node other) {
        return this.count - other.count;
    }
}

Upvotes: 1

Slaw
Slaw

Reputation: 46181

From the documentation of PriorityQueue:

An unbounded priority queue based on a priority heap. The elements of the priority queue are ordered according to their natural ordering, or by a Comparator provided at queue construction time, depending on which constructor is used. A priority queue does not permit null elements. A priority queue relying on natural ordering also does not permit insertion of non-comparable objects (doing so may result in ClassCastException). [emphasis added]

The documentation of PriorityQueue#add(E) states it can throw:

ClassCastException - if the specified element cannot be compared with elements currently in this priority queue according to the priority queue's ordering

And you create your PriorityQueue using the no-argument constructor, whose documentation states:

Creates a PriorityQueue with the default initial capacity (11) that orders its elements according to their natural ordering.

For an object to have a natural ordering it must implement the Comparable interface. Since your Node class does not implement Comparable you get a ClassCastException when adding the second element (due to there now being enough elements to start comparing them). There are at least two solutions:

  1. Have Node implement Comparable<Node>:

    public class Node implements Comparable<Node> {
    
        // fields and other methods omitted for brevity
    
        @Override // annotation forces compiler to check if method actually overrides anything
        public int compareTo(Node other) {
            // compare 'this' and 'other' based on their properties and return result...
        }
    }
    
  2. Pass a Comparator implementation when creating the PriorityQueue:

    PriorityQueue<Node> queue = new PriorityQueue<>((left, right) -> /* compare */);
    

Also see Java : Comparable vs Comparator [duplicate].

Upvotes: 1

nobody
nobody

Reputation: 11

Either Node must implement Comparable (as some answers suggest), or a Comparator must be provided when creating the PriorityQueue - according javadoc

An unbounded priority queue based on a priority heap. The elements of the priority queue are ordered according to their natural ordering, or by a Comparator provided at queue construction time, depending on which constructor is used. A priority queue does not permit null elements. A priority queue relying on natural ordering also does not permit insertion of non-comparable objects (doing so may result in ClassCastException).

Upvotes: 1

fpezzini
fpezzini

Reputation: 794

The first one worked because it's the only one. From the second it needs to compare it against the first one to know where to place it on the priority queue. You need to implement the interface Comparable on your Node class and implement the compare (a, b) method. Then the Priority queue will know how to properly order the items.

Upvotes: 5

Related Questions