是否有固定大小的队列来删除多余的元素?

时间:2009-12-26 17:01:35

标签: java queue

我需要一个固定大小的队列。当我添加一个元素并且队列已满时,它应该自动删除最旧的元素。

Java中是否存在此实现?

16 个答案:

答案 0 :(得分:102)

实际上LinkedHashMap完全符合您的要求。您需要覆盖removeEldestEntry方法。

具有最多10个元素的队列示例:

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

如果“removeEldestEntry”返回true,则从地图中删除最旧的条目。

答案 1 :(得分:58)

是,两个

my own duplicate question this correct answer开始,我学会了两个:

我有效地使用了番石榴EvictingQueue,效果很好。

答案 2 :(得分:17)

Java语言和运行时中没有现有的实现。所有队列都扩展AbstractQueue,其文档明确指出,向完整队列添加元素始终以异常结束。最好(并且非常简单)将Queue包装到您自己的类中以获得所需的功能。

再一次,因为所有队列都是AbstractQueue的子代,所以只需将其用作内部数据类型,您就应该在几乎没有时间运行灵活的实现: - )

更新:

如下所述,有两个开放的实现可用(这个答案已经很老了,伙计们!),详见this answer

答案 3 :(得分:15)

我刚刚以这种方式实现了固定大小的队列:

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 - 1);
        }
        return r;
    }

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

    public K getOldest() {
        return get(0);
    }
}

答案 4 :(得分:6)

这是我用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");
.....

答案 5 :(得分:4)

我认为你所描述的是一个循环队列。这是一个example,这里是一个better

答案 6 :(得分:3)

这个类使用组合而不是继承(这里的其他答案)来完成工作,这消除了某些副作用的可能性(如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();
    }
}

答案 7 :(得分:2)

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

答案 8 :(得分:0)

听起来像一个普通的List,其中add方法包含一个额外的片段,如果它太长,会截断列表。

如果这太简单了,那么您可能需要编辑问题描述。

答案 9 :(得分:0)

另请参阅this SO questionArrayBlockingQueue(请注意阻止,在您的情况下这可能不受欢迎)。

答案 10 :(得分:0)

目前尚不清楚您有什么要求导致您提出这个问题。如果您需要固定大小的数据结构,您可能还需要查看不同的缓存策略。但是,由于你有一个队列,我最好的猜测是你正在寻找某种类型的路由器功能。在这种情况下,我会使用一个环形缓冲区:一个具有第一个和最后一个索引的数组。每当添加一个元素时,您只需递增最后一个元素索引,并在删除元素时增加第一个元素索引。在这两种情况下,以数组大小为模进行加法,并确保在需要时递增另一个索引,即队列满或空时。

此外,如果它是路由器类型的应用程序,您可能还需要尝试一种算法,例如随机早期删除(RED),它会在填充之前随机丢弃队列中的元素。在某些情况下,发现RED的整体性能要好于允许队列在删除之前填满的简单方法。

答案 11 :(得分:0)

实际上你可以根据LinkedList编写自己的impl,它非常简单,只需覆盖add方法并完成工作。

答案 12 :(得分:0)

我认为最匹配的答案来自this other question

Apache commons集合4有CircularFifoQueue这就是你要找的东西。引用javadoc:

  

CircularFifoQueue是一个先进先出队列,具有固定大小,如果已满,则替换其最旧的元素。

答案 13 :(得分:0)

一个简单的解决方案,下面是&#34; String&#34;

的队列
LinkedHashMap<Integer, String> queue;
int queueKeysCounter;

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

请注意,这不会维护队列中项目的顺序,但会替换最旧的条目。

答案 14 :(得分:0)

如OOP中所建议,我们应该首选Composition over Inheritance

请记住我的解决方案。

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

答案 15 :(得分:0)

好吧,我也会扔掉我的版本。 :-)这是非常有效的构建-在那时候很重要。它不是基于LinkedList的-并且是线程安全的(至少应该是)。先进先出

static class FixedSizeCircularReference<T> {
    T[] entries

    FixedSizeCircularReference(int size) {
        this.entries = new Object[size] as T[]
        this.size = size
    }
    int cur = 0
    int size

    synchronized void add(T entry) {
        entries[cur++] = entry
        if (cur >= size) {
            cur = 0
        }
    }

    List<T> asList() {
        int c = cur
        int s = size
        T[] e = entries.collect() as T[]
        List<T> list = new ArrayList<>()
        int oldest = (c == s - 1) ? 0 : c
        for (int i = 0; i < e.length; i++) {
            def entry = e[oldest + i < s ? oldest + i : oldest + i - s]
            if (entry) list.add(entry)
        }
        return list
    }
}