Aşırı öğeleri ortadan kaldıran sabit boyutlu bir kuyruk var mı?


128

Sabit büyüklükte bir kuyruğa ihtiyacım var. Bir eleman eklediğimde ve sıra dolu olduğunda, en eski elemanı otomatik olarak kaldırması gerekir.

Java'da bunun için mevcut bir uygulama var mı?


Yanıtlar:


19

Java Dilinde ve Çalışma Zamanında mevcut bir uygulama yoktur. Tüm Kuyruklar AbstractQueue'yu genişletir ve dokümanı, tam kuyruğa bir öğe eklemenin her zaman bir istisna ile bittiğini açıkça belirtir. İhtiyaç duyduğunuz işlevselliğe sahip olmak için en iyisi (ve oldukça basit) bir Kuyruğu kendi sınıfınıza sarmaktır.

Bir kez daha, tüm kuyruklar AbstractQueue'nun çocukları olduğundan, bunu dahili veri türünüz olarak kullanın ve neredeyse hiç zaman harcamadan çalışan esnek bir uygulamaya sahip olmalısınız :-)

GÜNCELLEME:

Aşağıda özetlendiği gibi, iki açık uygulama vardır (bu cevap oldukça eski millet!), Ayrıntılar için bu yanıta bakın.


4
AbstractQueue yerine Kuyruk Kullan ... arabirimi uygulayan ancak soyut sınıfı genişletmeyen kuyruklar olabilir.
TofuBeer

1
Python'da, collection.dequebelirtilen bir maxlen.
Jonas Gröger

2
GÜNCELLEME Artık bu tür iki sınıf mevcuttur. Kendi yazmanıza gerek yok. Bkz Cevabımı bu sayfada.
Basil Bourque

108

Aslında LinkedHashMap tam olarak istediğinizi yapar. removeEldestEntryYöntemi geçersiz kılmanız gerekir .

En fazla 10 öğeli bir kuyruk örneği:

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

"RemoveEldestEntry" true değerini döndürürse, en eski girdi haritadan kaldırılır.


7
bu aslında bir kuyruğun yaptığını yapmaz, en yenisini nasıl alabilirim. nesne?
Alex

69

Evet, iki

Gönderen Kendi yinelenen soru ile bu doğru cevabı , ben ikisinin öğrendim:


Guava'yı verimli kullandım, EvictingQueueiyi çalıştı.

Bir EvictingQueuestatik fabrika yöntemini başlatmak için createve maksimum boyutunuzu belirtin.

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

... ve eğer Commons Collection 4.0'ı kullanamıyorsanız, CircularFifoBuffer, v 3.0'daki CircularFifoQueue'ye benzer görünüyor.
Sridhar Sarnobat

CircularFifoQueuebağlantı kesildi
user7294900

@ user7294900 Teşekkürler, bağlantı düzeltildi. Bilginize, Stack Overflow sizi bu tür düzenlemeleri doğrudan kendiniz bir Yanıta yapmaya davet ediyor. Yalnızca orijinal yazar değil, herkes düzenleyebilir. Stack Overflow, bu bakımdan Wikipedia'yı daha çok sevmeyi amaçlamaktadır.
Basil Bourque

@BasilBourque evet, ancak bu tür düzenlemeler bağlantıları değiştirirken bile reddedilebilir, gri bir alandır
user7294900

18

Bu şekilde sabit boyutlu bir sıra uyguladım:

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
O olmalıremoveRange(0, size() - maxSize)
Ahmet Hegazy

@AhmedHegazy removeRange (0, size () - maxSize - 1) doğru
Ashish Doneriya

Yukarıda Amhed'e katılıyorum. - 1'i kaldırın. Aksi takdirde maksimum kapasitede, 0 tabanlı olduğundan bahsettiğimiz için maxSize + 1 olan bir dizi elde edersiniz. Örneğin. MaxSize = 50 ise, yeni bir nesne eklerken orijinal gönderideki removeRange formülü 51 - 50 - 1 = 0 olacaktır (yani hiçbir şey kaldırılmamıştır).
2019

8

QueueSararak yaptığım LinkedListbu, burada verdiğim sabit büyüklükte 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

Bence tarif ettiğiniz şey döngüsel bir kuyruk. İşte bir olan örnek ve burada olduğunu daha iyi bir


4

Bu sınıf, işi miras yerine kompozisyon kullanarak yapar (burada diğer cevaplar), bu da belirli yan etkilerin olasılığını ortadan kaldırır (Essential Java'da Josh Bloch tarafından ele alındığı gibi). Temel LinkedList öğesinin kırpılması add, addAll ve offer yöntemlerinde gerçekleşir.

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

Kullanım ve test sonucu:

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 yönteminin, çok uzun olursa listeyi kesen fazladan bir parçacık içerdiği sıradan bir Listeye benziyor.

Bu çok basitse, muhtemelen sorun açıklamanızı düzenlemeniz gerekir.


Aslında, ilk öğeyi (yani en erken) silmesi gerekecekti, kısaltmak son öğeyi kaldıracaktır. LinkedList ile hala pratik.
MAK


0

Sizi bu soruyu sormaya sevk eden hangi gereksinimleriniz olduğu tam olarak belli değil. Sabit boyutlu bir veri yapısına ihtiyacınız varsa, farklı önbelleğe alma politikalarına da bakmak isteyebilirsiniz. Ancak, bir kuyruğunuz olduğundan, en iyi tahminim, bir tür yönlendirici işlevi aramanızdır. Bu durumda, bir halka tamponu ile giderdim: birinci ve son indeksi olan bir dizi. Bir eleman eklendiğinde, sadece son eleman endeksini arttırırsınız ve bir eleman kaldırıldığında, ilk eleman endeksini arttırırsınız. Her iki durumda da, dizi boyutunu modülo olarak ekleme gerçekleştirilir ve gerektiğinde, yani kuyruk dolu veya boş olduğunda diğer dizini artırdığınızdan emin olun.

Ayrıca, yönlendirici tipi bir uygulama ise, öğeleri doldurulmadan önce bile kuyruktan rasgele bırakan Random Early Dropping (RED) gibi bir algoritmayı da denemek isteyebilirsiniz. Bazı durumlarda RED'in, kuyruğun düşmeden önce dolmasına izin veren basit yöntemden daha iyi bir genel performansa sahip olduğu bulunmuştur.


0

Aslında LinkedList'e dayalı olarak kendi impl'inizi yazabilirsiniz, oldukça basittir, sadece add yöntemini geçersiz kılın ve personeli yapın.


0

Bence en uygun yanıt bu diğer sorudan geliyor .

Apache commons collections 4, aradığınız şey olan bir CircularFifoQueue'ye sahiptir. Javadoc'dan alıntı yapmak:

CircularFifoQueue, dolu olduğunda en eski öğesinin yerini alan sabit bir boyuta sahip ilk giren ilk çıkar kuyruğudur.


0

Basit bir çözüm, aşağıda bir "Dize" Sırasıdır

LinkedHashMap<Integer, String> queue;
int queueKeysCounter;

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

Bunun Kuyruktaki öğelerin Sırasını korumayacağını, ancak en eski girişin yerini alacağını unutmayın.


0

OOP'larda tavsiye edildiği gibi , Miras yerine Bileşimi tercih etmemiz gerekir

İşte bunu akılda tutarak benim çözümüm.

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();
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.