簡體   English   中英

使 Java PriorityQueue 成為穩定的優先級隊列

[英]Making a Java PriorityQueue into a stable priority queue

我正在嘗試在 Java 中實現一個穩定的(先進先出)優先級隊列。 假設鍵是一個名字,值是一個年齡,我知道我可以像這樣制作一個不穩定的優先級隊列:

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

這幾乎完成了我需要它做的所有事情,除了它在我插入(或刪除它們)時不保持鍵值對的順序。

我通過制作 LinkedList 找到了一種“解決方法”,它提供了基本上所有相同的功能,只是它不包含帶有比較器選項的構造函數,而且我覺得它必須更慢,因為我保持了值排序通過在每個隊列操作之后調用Collections.sort()

所以我想確實有兩個我感興趣的選項。首先,我如何編輯上面的 PriorityQueue 以保持插入和刪除順序? 或者第二,如何強制我的 LinkedList 選項立即使用比較器,而不必對每個操作調用排序? 謝謝!

編輯:

感謝您在發布的第一條評論中提出的好問題。 通過FIFO,我的意思是對於具有相等值的鍵值對,應該首先提取最先放入的鍵值對。

你需要這樣的東西:

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

基於 Keap 的 PriorityQueue自然是穩定的。 它是用 Kotlin 編寫的,因此它可以替換 Java 代碼java.util.PriorityQueue

基於多個列表和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內部用於隊列。 我的情況是我只有幾個優先級,但有很多元素,所以它應該比使用元素比較的東西更快。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM