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


回答:


19

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

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

更新:

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


4
AbstractQueueの代わりにQueueを使用してください...インターフェイスを実装するが、抽象クラスを拡張しないキューがある場合があります。
豆腐ビール2009

1
Pythonではcollection.deque、を指定して使用できますmaxlen
JonasGröger、2014

2
更新現在、このようなクラスが2つ利用可能です。自分で書く必要はありません。参照してください私の答えこのページを。
バジルブルク2014

107

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

最大10要素のキューの例:

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

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


7
これは実際にはキューが行うことを実行しません。どうすれば最新のものを取得できますか。オブジェクト?
Alex

69

はい、2

この正しい答えを含む自分自身の重複した質問から、私は2つのことを学びました:


私はグアバを生産的に利用しEvictingQueue、うまくいきました。

EvictingQueue静的なファクトリメソッドcreateを呼び出して最大サイズを指定するには、インスタンスを作成します。

EvictingQueue< Person > people = com.google.common.collect.EvictingQueue.create( 100 ) ;  // Set maximum size to 100. 

...そしてCommons Collection 4.0を使用できない場合、CircularFifoBufferはv 3.0のCircularFifoQueueに似ているようです。
Sridhar Sarnobat

CircularFifoQueueリンクが無効です。
user7294900

@ user7294900おかげで、リンクが修正されました。ちなみに、Stack Overflowでは、このような編集を直接自分でAnswerに加えるように勧めています。元の作者だけでなく、誰でも編集できます。スタックオーバーフローは、その点でウィキペディアに似ていることを目的としています。
バジルブルク2018年

@BasilBourqueはい。ただし、リンクを変更すると、私でもこのような編集を拒否できます。これは、灰色の領域です
user7294900

18

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

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

1
それはする必要がありますremoveRange(0, size() - maxSize)
アハメド・ヘガジー

@AhmedHegazy removeRange(0、size()-maxSize-1)は正しい
Ashish Doneriya

上記のAmhedに同意します。-1を削除します。それ以外の場合、最大容量では、0をベースに話しているため、maxSize + 1の配列になります。例えば。maxSize = 50の場合、新しいオブジェクトを追加すると、元の投稿のremoveRange式は51-50-1 = 0になります(つまり、何も削除されません)。
Etep、

8

これは、で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");
.....

4

あなたが説明しているのは循環キューだと思います。ここにがあり、これはより良いものです


4

このクラスは、継承(代わりに他の回答)ではなく構成を使用して作業を行います(これにより、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();
    }
}

3
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]
}

0

通常のリストのように聞こえますが、addメソッドには、リストが長すぎる場合にリストを切り捨てる追加のスニペットが含まれています。

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


実際には、彼は最初の要素(つまり最も古い要素)を削除する必要があり、切り捨てると最後の要素が削除されます。LinkedListを使用してもまだ実用的です。
MAK、


0

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

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


0

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


0

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

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

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


0

以下の簡単な解決策は、「文字列」のキューです

LinkedHashMap<Integer, String> queue;
int queueKeysCounter;

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

これはキュー内のアイテムの順序を維持しませんが、最も古いエントリを置き換えます。


0

OOPでアドバイスされているように、継承よりも構成を優先する必要があります

ここでそれを念頭に置いて私の解決策。

package com.choiceview;

import java.util.ArrayDeque;

class Ideone {
    public static void main(String[] args) {
        LimitedArrayDeque<Integer> q = new LimitedArrayDeque<>(3);
        q.add(1);
        q.add(2);
        q.add(3);
        System.out.println(q);

        q.add(4);
        // First entry ie 1 got pushed out
        System.out.println(q);
    }
}

class LimitedArrayDeque<T> {

    private int maxSize;
    private ArrayDeque<T> queue;

    private LimitedArrayDeque() {

    }

    public LimitedArrayDeque(int maxSize) {
        this.maxSize = maxSize;
        queue = new ArrayDeque<T>(maxSize);
    }

    public void add(T t) {
        if (queue.size() == maxSize) {
            queue.removeFirst();
        }
        queue.add(t);
    }

    public boolean remove(T t) {
        return queue.remove(t);
    }

    public boolean contains(T t) {
        return queue.contains(t);
    }

    @Override
    public String toString() {
        return queue.toString();
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.