【问题标题】:Making a Java PriorityQueue into a stable priority queue使 Java PriorityQueue 成为稳定的优先级队列
【发布时间】:2014-03-04 05:40:08
【问题描述】:

我正在尝试在 Java 中实现一个稳定的(先进先出)优先级队列。假设键是名称,值是年龄,我知道我可以像这样制作一个不稳定的优先级队列:

Queue<Map.Entry<String, Integer>> pq = new PriorityQueue<Map.Entry<String, Integer>>(100, ageComparator);

这几乎完成了我需要它做的所有事情,除了它在我插入(或删除它们)时不保持键值对的顺序。

我通过制作 LinkedList 找到了一种“解决方法”,它提供了基本上所有相同的功能,只是它不包含带有比较器选项的构造函数,而且我觉得它必须更慢,因为我在每次队列操作后调用Collections.sort() 来维护值顺序。

所以我想确实有两个我感兴趣的选项。首先,我如何编辑上面的 PriorityQueue 以保持插入和删除顺序?或者第二,如何强制我的 LinkedList 选项立即使用比较器,而不必对每个操作调用排序?谢谢!

编辑:

感谢您在发布的第一条评论中提出的好问题。先进先出,我的意思是对于值相等的键值对,首先放入的键值对应该先提取。

【问题讨论】:

  • 您到底在调用 FIFO 优先级队列什么?你的意思是它对于同等优先级的项目是 FIFO 吗?
  • @JimGarrison - 好问题;是的,这就是我的意思。因此,如果我插入 ("Alice", 30) 然后 ("Bob", 30),那么提取应该给我 Alice 然后是 Bob。

标签: java linked-list queue priority-queue comparator


【解决方案1】:

你需要这样的东西:

import java.util.AbstractMap;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.concurrent.atomic.AtomicInteger;

public class PriorityTest {
  @SuppressWarnings("serial")
  private static class Entry extends AbstractMap.SimpleEntry<String, Integer> {
    private final static AtomicInteger seq = new AtomicInteger(0);
    final int order;
    public Entry(final String _key, final Integer _value) {
      super(_key, _value);
      order = seq.incrementAndGet();
    }
  }

  private static class OrderedComparator implements Comparator<Entry> {
    @Override
    public int compare(final Entry _e1, final Entry _e2) {
      int r = _e1.getValue().compareTo(_e2.getValue());
      if (r == 0)
        return Integer.compare(_e1.order, _e2.order);
      return r;
    }
  }

  public static void main(String[] args) {
    final PriorityQueue<Entry> pq = new PriorityQueue<Entry>(10, new OrderedComparator());
    pq.add(new Entry("Jane", 22));
    pq.add(new Entry("John", 15));
    pq.add(new Entry("Bill", 45));
    pq.add(new Entry("Bob", 22));
    while(!pq.isEmpty()) {
      System.out.println(pq.remove());
    }
  }
}

【讨论】:

    【解决方案2】:

    Keap-based PriorityQueue 自然是稳定的。它是用 Kotlin 编写的,因此可以替换 Java 代码中的java.util.PriorityQueue

    【讨论】:

      【解决方案3】:

      基于多个列表和TreeMap的非常简单的实现我今天已经完成了一些任务:

      import javax.annotation.Nonnull;
      import java.util.*;
      import java.util.Map.Entry;
      import java.util.function.Function;
      
      public class PriorityFifo<E> {
      
           protected TreeMap<Integer, LinkedList<E>> storage = new TreeMap<>();
      
           public void push(E element, int priority) {
              storage.computeIfAbsent(priority, it -> new LinkedList<>()).addLast(element);
           }
      
           public Optional<E> poll() {
              return doWithNextElement(LinkedList::pollFirst);
           }
      
           public Optional<E> peek() {
              return doWithNextElement(LinkedList::getFirst);
           }
      
           protected Optional<E> doWithNextElement(@Nonnull Function<LinkedList<E>, E> f) {
               Entry<Integer, LinkedList<E>> entry = storage.firstEntry();
               if (entry==null)
                   return Optional.empty();
               LinkedList<E> list = entry.getValue();
               E element = f.apply(list);
               if (list.isEmpty())
                   storage.remove(entry.getKey());
               return Optional.of(Objects.requireNonNull(element));
      
           }
      
      }
      

      没有用于元素的比较器,但在TreeMap 内部用于队列。我的情况是我只有几个优先级,但有很多元素,所以它应该比使用元素比较的东西更快。

      【讨论】:

        猜你喜欢
        • 2012-06-15
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-07
        • 2012-09-25
        相关资源
        最近更新 更多