【问题标题】:Why does PriorityQueue.toString return the wrong element order? [duplicate]为什么 PriorityQueue.toString 返回错误的元素顺序? [复制]
【发布时间】:2015-03-04 13:43:34
【问题描述】:

我正在尝试在 java 中使用优先级频率最低的节点创建一个优先级队列。但是,我的比较器不工作,输出很奇怪。我相信我需要更改我的比较器,但我不知道如何更改它。 这是我的代码:

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);
}
}

输出如下: [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 , 一个]。

但是,输出应该是[z, q, x, j, k, v, b........]。

【问题讨论】:

  • @LuiggiMendoza: toString 使用迭代器显示所有对象。
  • @LuiggiMendoza 从我在 AbstractCollection 的代码中看到的,toString 使用了一个迭代器,所以它应该按遍历的顺序打印元素。这是 PriorityQueue 使用的 toString 的实现(至少在 Java 6 中)。
  • 文档说:The Iterator provided in method iterator() is not guaranteed to traverse the elements of the priority queue in any particular order.
  • @Eran 迭代器不能这样做,它是一个堆。如果不实际修改集合,就无法对其进行排序。
  • 如果您想要一个结构可以按顺序返回元素而不改变结构,请使用TreeSet 而不是PriorityQueue

标签: java sorting printing comparator priority-queue


【解决方案1】:

您需要逐一轮询PriorityQueue 中的项目。 toString 不会那样做。

所以不要使用System.out.println(queue);,而是这样做:

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

原因是PriorityQueue 从未在内部完全排序,请查看堆如何工作以获取更多详细信息。从它轮询项目在调用期间修复堆,因此它应该按排序顺序输出元素。

【讨论】:

    【解决方案2】:

    System.out.println(queue) 正在打印未排序的队列。如果您想打印队列的真实顺序,请按照以下代码使用 poll 从队列上到下获取元素:

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

    你会看到预期的输出:

    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,

    【讨论】:

      【解决方案3】:

      您希望较低的频率更高:

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

      如果您想对其进行测试,请将其发送到单线程池并查看正在处理的作业的顺序,而不是字符串或迭代器。正如文档在http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#iterator%28%29 所说:

      返回此队列中元素的迭代器。迭代器不会以任何特定顺序返回元素。

      可以查看http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor%28%29 以获得快速的单线程池来对此进行测试。

      【讨论】:

        【解决方案4】:

        @Thomas 回答有效。

        我的方法是产生相同的结果实际上不清空队列。因此,我在PriorityQueue 上创建了一个包装器,并为它实现了next()hasNext()。此外,为了准确模拟优先队列行为,extend AbstractQueuedelegate 通过 PriorityQueue 对象调用 offerpeekpollsize 等方法。

        priorityQueueObject.methodName()
        

        免责声明:这确实需要将整个队列复制到一个列表中并对其进行排序。

        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();
            }
        }
        

        打印:

        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, 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-12-22
          • 1970-01-01
          • 2013-05-27
          • 2016-08-10
          相关资源
          最近更新 更多