【问题标题】:PriorityQueue has objects with the same priorityPriorityQueue 具有相同优先级的对象
【发布时间】:2013-03-31 16:55:19
【问题描述】:

我正在使用优先级队列对大量自定义对象进行排序和使用。对象有一个“重量”,这是它们的自然顺序。但是,插入优先级队列的不同对象可能具有相同的“权重”。在这种情况下,我希望优先级队列按照它们放入队列的顺序对它们进行排序。

例如,如果我按该顺序添加 CustomObjects A、B、C、D,它们都具有相同的“权重”,那么优先级队列也应该按该顺序返回它们 - 即使我轮询一个或多个在添加其他对象之前的对象。

这是我的自定义对象的 CompareTo:

public int compareTo(CustomObject o) {
    int thisWeight = this.weight;
    int thatWeight = o.weight;
    if(thisWeight < thatWeight){
        return -1;
    }
    else{
        return 1;
    }
}

虽然我认为这会保持最初的顺序,但事实并非如此。当我输入权重为 1 的 A、B、C 时会发生这种情况;投票A;并添加权重为 1 的 D,E。不知何故,D 和 E 排序在 B 之后,但在 C 之前。

我知道 PriorityQueues 的迭代器没有返回正确的顺序,因此我查看顺序的能力有限 - 但是我可以看到元素离开队列的顺序,但显然没有按照我想要的路径。

建议?

【问题讨论】:

    标签: java priority-queue


    【解决方案1】:

    如果您需要根据插入顺序进行排序,则需要为时间戳使用额外的元素。 IE。在插入和相等权重上使用timestamp 来查看首先插入的元素。 所以CustomObject 应该是这样的:

    class CustomObject {  
       int weight;  
       long timestamp;  
    }
    

    比较应该是:

    public int compareTo (CustomObject o) {  
        int thisWeight = this.weight;  
        int thatWeight = o.weight;  
        if (thisWeight != thatWeight) {  
            return thisWeight - thatWeight;  
        }  
        else {  
            return this.timestamp - o.timestamp;  
        }  
    }  
    

    较小的timestamp 表示它被插入较早,因此您保持插入顺序。

    您还可以通过维护一个计数器来使用“逻辑”时间,并在每个addremove 上更新该计数器。

    【讨论】:

    • 我刚刚修改了自己的 compareTo,添加了一个额外的 if else 语句。但至于答案的实际内容 - 完美,谢谢!
    • 这适用于插入,但是当我弹出时,顺序再次发生变化。有没有办法解决这个问题?
    【解决方案2】:

    您可以使用自动递增的序列号作为辅助键,并使用它来打破平局。

    PriorityBlockingQueue 的 Javadoc 包含此技术的示例:

    对此类的操作不保证具有相同优先级的元素的顺序。如果您需要强制执行排序,您可以定义自定义类或比较器,它们使用辅助键来打破主要优先级值的关系。例如,这里有一个类将先进先出的平局应用于可比较的元素。要使用它,您需要插入一个新的 FIFOEntry(anEntry) 而不是一个普通的条目对象。

    class FIFOEntry<E extends Comparable<? super E>>
         implements Comparable<FIFOEntry<E>> {
       final static AtomicLong seq = new AtomicLong();
       final long seqNum;
       final E entry;
       public FIFOEntry(E entry) {
         seqNum = seq.getAndIncrement();
         this.entry = entry;
       }
       public E getEntry() { return entry; }
       public int compareTo(FIFOEntry<E> other) {
         int res = entry.compareTo(other.entry);
         if (res == 0 && other.entry != this.entry)
           res = (seqNum < other.seqNum ? -1 : 1);
         return res;
       }
     }
    

    【讨论】:

      猜你喜欢
      • 2022-01-16
      • 2011-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-22
      • 1970-01-01
      • 2017-01-13
      • 2015-05-23
      相关资源
      最近更新 更多