16

I am trying to make a priority queue in java with the nodes with the lowest frequency in priority. However, my comparator is not working and the output is very weird. I believe I need to change my comparator but I am not sure how to change it. Here is my code:

public class HuffmanComparator implements Comparator<TreeNodeHuffman> {
    public int compare(TreeNodeHuffman p1, TreeNodeHuffman p2) {
        if (p1.frequency < p2.frequency) return -1;
        if (p1.frequency > p2.frequency) return 1;
        return 0;
    }    
}

public class TreeNodeHuffman {
public static void main(String[] args) {    
    HuffmanComparator compare = new HuffmanComparator();
    TreeNodeHuffman e = new TreeNodeHuffman('e', 12702);
    TreeNodeHuffman t = new TreeNodeHuffman('t', 9056);
    TreeNodeHuffman a = new TreeNodeHuffman('a', 8167);
    TreeNodeHuffman o = new TreeNodeHuffman('o', 7507);
    TreeNodeHuffman i = new TreeNodeHuffman('i', 6966);
    TreeNodeHuffman n = new TreeNodeHuffman('a', 6749);
    TreeNodeHuffman s = new TreeNodeHuffman('s', 6327);
    TreeNodeHuffman h = new TreeNodeHuffman('h', 6094);
    TreeNodeHuffman r = new TreeNodeHuffman('r', 5987);
    TreeNodeHuffman d = new TreeNodeHuffman('d', 4253);
    TreeNodeHuffman l = new TreeNodeHuffman('l', 4025);
    TreeNodeHuffman c = new TreeNodeHuffman('c', 2782);
    TreeNodeHuffman u = new TreeNodeHuffman('u', 2758);
    TreeNodeHuffman m = new TreeNodeHuffman('m', 2406);
    TreeNodeHuffman w = new TreeNodeHuffman('w', 2360);
    TreeNodeHuffman f = new TreeNodeHuffman('f', 2228);
    TreeNodeHuffman g = new TreeNodeHuffman('g', 2015);
    TreeNodeHuffman y = new TreeNodeHuffman('y', 1974);
    TreeNodeHuffman p = new TreeNodeHuffman('p', 1929);
    TreeNodeHuffman b = new TreeNodeHuffman('b', 1492);
    TreeNodeHuffman v = new TreeNodeHuffman('v', 978);
    TreeNodeHuffman k = new TreeNodeHuffman('k', 772);
    TreeNodeHuffman j = new TreeNodeHuffman('j', 153);
    TreeNodeHuffman x = new TreeNodeHuffman('x', 150);
    TreeNodeHuffman q = new TreeNodeHuffman('q', 95);
    TreeNodeHuffman z = new TreeNodeHuffman('z', 74);
    PriorityQueue<TreeNodeHuffman> queue = new PriorityQueue<TreeNodeHuffman>(26, compare);
    queue.add(e);
    queue.add(t);
    queue.add(a);
    queue.add(o);
    queue.add(i);
    queue.add(n);
    queue.add(s);
    queue.add(h);
    queue.add(r);
    queue.add(d);
    queue.add(l);
    queue.add(c);
    queue.add(u);
    queue.add(m);
    queue.add(w);
    queue.add(f);
    queue.add(g);
    queue.add(y);
    queue.add(p);
    queue.add(b);
    queue.add(v);
    queue.add(k);
    queue.add(j);
    queue.add(x);
    queue.add(q);
    queue.add(z);
    System.out.println(queue);
}
}

The output is as follows: [z, k, q, g, v, x, u, d, f, y, b, m, j, i, c, e, s, o, w, a, r, h, p, t, l, a].

However, the output should be [z, q, x, j, k, v, b........].

TylerH
  • 20,799
  • 66
  • 75
  • 101
loolooo
  • 181
  • 1
  • 7
  • 4
    @LuiggiMendoza: `toString` uses the iterator to display all objects. – njzk2 Jan 06 '15 at 20:09
  • 2
    @LuiggiMendoza From what I see in the code of AbstractCollection, toString uses an iterator, so it should print the elements in the order of traversal. That's the implementation of toString used by PriorityQueue (at least in Java 6). – Eran Jan 06 '15 at 20:10
  • 5
    The Doc says: `The Iterator provided in method iterator() is not guaranteed to traverse the elements of the priority queue in any particular order.` – njzk2 Jan 06 '15 at 20:12
  • 2
    @Eran the iterator can't do that, it is a heap. You can't have it sorted without actually modifying the collection. – Thomas Jungblut Jan 06 '15 at 20:13
  • 3
    If you want a structure that will return the elements in order without altering the structure, use a `TreeSet` instead of a `PriorityQueue`. – ajb Jan 06 '15 at 20:15
  • @loolooo I am not sure `PriorityQueue` is best suited here. Consider a simple List and Collections.sort using your comparator, or maybe a `TreeSet` – njzk2 Jan 06 '15 at 20:16

4 Answers4

31

You need to poll the items from the PriorityQueue one by one. toString doesn't do that.

So instead of your System.out.println(queue); do this:

while(!queue.isEmpty()) {
   System.out.println(queue.poll());
}

The reason is that the PriorityQueue is never completely sorted internally, lookup how a heap works for more detail. Polling items from it fixes the heap during the calls, thus it should output the elements in sorted order.

Thomas Jungblut
  • 20,854
  • 6
  • 68
  • 91
6

The System.out.println(queue) is printing the queue unsorted. If you want to print the queue real order follow the below code which use poll to get the elements from the queue top to bottom:

TreeNodeHuffman tn = null;
    do{
        tn = queue.poll();
        if(tn!=null){
            System.out.print(tn.key+",");
        }
    }while(tn != null);

and you shall see this output as expected:

z,q,x,j,k,v,b,p,y,g,f,w,m,u,c,l,d,r,h,s,a,i,o,a,t,e,

2

You want lower frequency to go higher so :

  public int compare(TreeNodeHuffman p1, TreeNodeHuffman p2) {
          if (p1.frequency < p2.frequency) return 1;
          if (p1.frequency > p2.frequency) return -1;
          return 0;
      }    
   }

If you want to test it, send it to a single threaded pool and see the order of jobs being processed instead of to string or iterator. as doc says at http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#iterator%28%29 :

Returns an iterator over the elements in this queue. The iterator does not return the elements in any particular order.

Can see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor%28%29 for a quick single threaded pool to test this.

tgkprog
  • 4,493
  • 4
  • 41
  • 70
0

@Thomas answer works.

My approach is to produce same result without actually emptying the queue . So, instead I created a wrapper over the PriorityQueue, and implemented next() and hasNext() for it. Also, to exactly simulate the priority queue behavior, extend AbstractQueue and delegate calls to methods like offer, peek, poll and size through PriorityQueue object.

priorityQueueObject.methodName()

Disclaimer: This does cost copying the whole queue into a list and doing the sorting over it.

public class MyPriorityQueue<E extends Comparable<T>, T> extends AbstractQueue<E> {
    Integer arrOfInts[] = { 11, 7, 15, 10, 2, 1, 4, 5, 7, 2, 18, 1, 19};
    PriorityQueue<E> pq = new PriorityQueue<>();

    public static void main(String[] args) {
        MyPriorityQueue mpq = new MyPriorityQueue<>();
        mpq.addAll(Arrays.asList(arrOfInts));

        //Using iterator
        Iterator it = mpq.iterator();
        System.out.println("The internal priority queue:"  + mpq.pq);
        System.out.println("Using Iterator:");
        while(it.hasNext()) {
            System.out.print(it.next() + ", ");
        }

        System.out.println("\nUsing simple system out println:");
        System.out.println(mpq);

        System.out.println("Using foreach: ");
        for(Object o : mpq) {
            System.out.print(o + ", ");
        }
    }

    @Override
    public boolean offer(E arg0) {
        return pq.offer(arg0);
    }

    @Override
    public E peek() {
        return pq.peek();
    }

    @Override
    public E poll() {
        return pq.poll();
    }

    @Override
    public Iterator<E> iterator() {
        ArrayList<E> list = new ArrayList(Arrays.asList(pq.toArray()));
        Collections.sort(list, null);
        return new Iterator<E>() {
            @Override
            public boolean hasNext() {
                return !list.isEmpty();
            }

            @Override
            public E next() {
                assert (hasNext());
                return list.remove(0);
            }
        };
    }

    @Override
    public int size() {
        return pq.size();
    }
}

prints:

The internal priority queue:[1, 2, 1, 7, 5, 2, 4, 11, 7, 10, 18, 15, 19]
Using Iterator:
1, 1, 2, 2, 4, 5, 7, 7, 10, 11, 15, 18, 19, 
Using simple system out println:
[1, 1, 2, 2, 4, 5, 7, 7, 10, 11, 15, 18, 19]
Using foreach: 
1, 1, 2, 2, 4, 5, 7, 7, 10, 11, 15, 18, 19, 
Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79