web-dev-qa-db-ja.com

余分な要素を削除する固定サイズのキューはありますか?

固定サイズのキューが必要です。要素を追加してキューがいっぱいになると、最も古い要素が自動的に削除されます。

これにはJavaの既存の実装がありますか?

114
c0d3x

Java言語とランタイム。すべてのキューは AbstractQueue を拡張します。そのドキュメントには、完全なキューへの要素の追加は常に最後で終わると明記されています。例外:必要な機能を得るために、キューを独自のクラスにラップするのが最適です(非常に単純です)。

繰り返しになりますが、すべてのキューはAbstractQueueの子であるため、内部データ型として使用するだけで、実質的に短時間で柔軟な実装を実行できます。

更新:

以下に概説するように、2つのオープンな実装が利用可能です(この答えはかなり古いです!)。詳細については この答え を参照してください。

17
moritz

実際には、 LinkedHashMap はまさにあなたが望むことをします。 removeEldestEntryメソッドをオーバーライドする必要があります。

最大10個の要素を持つキューの例:

  queue = new LinkedHashMap<Integer, String>()
  {
     @Override
     protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest)
     {
        return this.size() > 10;   
     }
  };

「removeEldestEntry」がtrueを返す場合、最も古いエントリがマップから削除されます。

104
Mavrik

はい、2

自分の重複した質問この正解 から、2つのことを学びました:

私はGuava EvictingQueueを生産的に使用しましたが、うまくいきました。

60
Basil Bourque

この方法で固定サイズのキューを実装しました。

public class LimitedSizeQueue<K> extends ArrayList<K> {

    private int maxSize;

    public LimitedSizeQueue(int size){
        this.maxSize = size;
    }

    public boolean add(K k){
        boolean r = super.add(k);
        if (size() > maxSize){
            removeRange(0, size() - maxSize);
        }
        return r;
    }

    public K getYoungest() {
        return get(size() - 1);
    }

    public K getOldest() {
        return get(0);
    }
}
18
Roar Skullestad

これは私がQueueでラップしたLinkedListでしたことです。ここで与える固定サイズは2です。

public static Queue<String> pageQueue;

pageQueue = new LinkedList<String>(){
            private static final long serialVersionUID = -6707803882461262867L;

            public boolean add(String object) {
                boolean result;
                if(this.size() < 2)
                    result = super.add(object);
                else
                {
                    super.removeFirst();
                    result = super.add(object);
                }
                return result;
            }
        };


....
TMarket.pageQueue.add("ScreenOne");
....
TMarket.pageQueue.add("ScreenTwo");
.....
7
Berkay Turancı

あなたが説明しているのは循環キューだと思います。ここに があり、ここに ベター があります

4
Sergey

このクラスは、特定の副作用(Essential JavaのJosh Blochでカバーされている)の可能性を排除する、継承(ここでは他の回答)ではなく合成を使用してジョブを実行します。基になるLinkedListのトリミングは、メソッドadd、addAll、offerで行われます。

import Java.util.Collection;
import Java.util.Iterator;
import Java.util.LinkedList;
import Java.util.Queue;

public class LimitedQueue<T> implements Queue<T>, Iterable<T> {

    private final int limit;
    private final LinkedList<T> list = new LinkedList<T>();

    public LimitedQueue(int limit) {
        this.limit = limit;
    }

    private boolean trim() {
        boolean changed = list.size() > limit;
        while (list.size() > limit) {
            list.remove();
        }
        return changed;
    }

    @Override
    public boolean add(T o) {
        boolean changed = list.add(o);
        boolean trimmed = trim();
        return changed || trimmed;
    }

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

    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return list.contains(o);
    }

    @Override
    public Iterator<T> iterator() {
        return list.iterator();
    }

    @Override
    public Object[] toArray() {
        return list.toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return list.toArray(a);
    }

    @Override
    public boolean remove(Object o) {
        return list.remove(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return list.containsAll(c);
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        boolean changed = list.addAll(c);
        boolean trimmed = trim();
        return changed || trimmed;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return list.removeAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return list.retainAll(c);
    }

    @Override
    public void clear() {
        list.clear();
    }

    @Override
    public boolean offer(T e) {
        boolean changed = list.offer(e);
        boolean trimmed = trim();
        return changed || trimmed;
    }

    @Override
    public T remove() {
        return list.remove();
    }

    @Override
    public T poll() {
        return list.poll();
    }

    @Override
    public T element() {
        return list.element();
    }

    @Override
    public T peek() {
        return list.peek();
    }
}
4
Dave Moten
public class CircularQueue<E> extends LinkedList<E> {
    private int capacity = 10;

    public CircularQueue(int capacity){
        this.capacity = capacity;
    }

    @Override
    public boolean add(E e) {
        if(size() >= capacity)
            removeFirst();
        return super.add(e);
    }
}

使用法とテスト結果:

public static void main(String[] args) {
    CircularQueue<String> queue = new CircularQueue<>(3);
    queue.add("a");
    queue.add("b");
    queue.add("c");
    System.out.println(queue.toString());   //[a, b, c]

    String first = queue.pollFirst();       //a
    System.out.println(queue.toString());   //[b,c]

    queue.add("d");
    queue.add("e");
    queue.add("f");
    System.out.println(queue.toString());   //[d, e, f]
}
2
Leon

Addメソッドに余分なスニペットが含まれている通常のリストのように聞こえますが、リストが長くなりすぎるとリストが切り捨てられます。

それが単純すぎる場合は、おそらく問題の説明を編集する必要があります。

this SO question 、または ArrayBlockingQueue も参照してください(ブロッキングに注意してください、これはあなたの場合は望ましくないかもしれません)。

0
Zoran Regvart

この質問をすることになった要件は明確ではありません。固定サイズのデータ​​構造が必要な場合は、さまざまなキャッシュポリシーを確認することもできます。ただし、キューがあるので、いくつかの種類のルーター機能を探しているのではないかと思います。その場合、リングバッファーを使用します。最初と最後のインデックスを持つ配列です。要素が追加されるたびに、最後の要素のインデックスをインクリメントし、要素が削除されると、最初の要素のインデックスをインクリメントします。どちらの場合も、追加は配列サイズを法として実行され、必要に応じて、つまりキューがいっぱいまたは空になったときに他のインデックスをインクリメントするようにしてください。

また、ルータータイプのアプリケーションの場合、キューが満杯になる前にランダムに要素をキューから削除するRandom Early Dropping(RED)などのアルゴリズムを試すこともできます。場合によっては、REDがキューをドロップする前にいっぱいにする単純な方法よりも全体的なパフォーマンスが優れていることがわかっています。

0
JaakkoK

以下の単純なソリューションは、「文字列」のキューです

LinkedHashMap<Integer, String> queue;
int queueKeysCounter;

queue.put(queueKeysCounter++, "My String");
queueKeysCounter %= QUEUE_SIZE;

これにより、キュー内のアイテムの順序は維持されませんが、最も古いエントリが置き換えられることに注意してください。

0
M. Usman Khan

最適な答えは この他の質問 からだと思います。

Apache commons collections 4には CircularFifoQueue があり、これが探しています。 javadocの引用:

CircularFifoQueueは、サイズが最も古い先入れ先出しキューで、満杯の場合は最も古い要素を置き換えます。

0
Diego

実際、LinkedListに基づいて独自の実装を記述できます。これは非常に簡単で、addメソッドをオーバーライドしてスタッフを実行するだけです。

0
Mike