과도한 요소를 제거하는 고정 크기의 큐가 있습니까?


127

고정 크기의 대기열이 필요합니다. 요소를 추가하고 대기열이 가득 차면 가장 오래된 요소가 자동으로 제거됩니다.

Java로 기존 구현이 있습니까?


답변:


19

Java 언어 및 런타임에는 기존 구현이 없습니다. 모든 큐는 AbstractQueue를 확장 하고 문서는 전체 큐에 요소를 추가하는 것이 항상 예외로 끝나는 것으로 명확하게 설명합니다. 필요한 기능을 갖추기 위해 대기열을 자신의 클래스로 포장하는 것이 가장 쉽고 간단합니다.

다시 한 번, 모든 큐는 AbstractQueue의 자식이므로 간단히이를 내부 데이터 유형으로 사용하면 사실상 짧은 시간 내에 유연한 구현을 수행해야합니다. :-)

최신 정보:

아래에 설명 된 것처럼 두 가지 공개 구현이 가능합니다 (이 답변은 상당히 오래되었습니다!) . 자세한 내용 은 이 답변 을 참조하십시오.


4
AbstractQueue 대신 Queue를 사용하십시오. 인터페이스를 구현하지만 추상 클래스를 확장하지 않는 대기열이있을 수 있습니다.
TofuBeer

1
파이썬에서는 지정된와 collection.deque함께를 사용할 수 있습니다 maxlen.
Jonas Gröger

2
업데이트 이제 사용 가능한 두 가지 클래스가 있습니다. 직접 작성할 필요가 없습니다. 보기 내 대답 이 페이지를.
Basil Bourque

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

네, 둘

에서 내 자신의 중복 된 질문이 정답 , 나는이 알게 :


나는 구아바를 생산적으로 사용하고 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링크는 죽은 사용하는 대신입니다 commons.apache.org/proper/commons-collections/apidocs/org/...
user7294900

@ user7294900 감사합니다. 링크가 수정되었습니다. 참고로, Stack Overflow는 이러한 편집을 직접 Answer에 직접 작성하도록 초대합니다. 원본 작성자뿐만 아니라 누구나 편집 할 수 있습니다. 스택 오버플로는 이와 관련하여 Wikipedia와 유사합니다.
Basil Bourque

@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)
Ahmed Hegazy 님이

@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

이 클래스는 상속 대신 컴포지션을 사용하여 작업을 수행합니다 (여기의 답변은 여기에 있습니다). 기본 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를 기반으로 자신의 impl을 작성할 수 있습니다. 정말 간단합니다 .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.