Gibt es eine Warteschlange mit fester Größe, die übermäßige Elemente entfernt?
127
Ich brauche eine Warteschlange mit einer festen Größe. Wenn ich ein Element hinzufüge und die Warteschlange voll ist, sollte das älteste Element automatisch entfernt werden.
In Java Language und Runtime ist keine Implementierung vorhanden. Alle Warteschlangen erweitern AbstractQueue , und in seinem Dokument wird eindeutig angegeben, dass das Hinzufügen eines Elements zu einer vollständigen Warteschlange immer mit einer Ausnahme endet. Es ist am besten (und ganz einfach), eine Warteschlange in eine eigene Klasse zu packen, um die Funktionalität zu erhalten, die Sie benötigen.
Da alle Warteschlangen untergeordnete Elemente von AbstractQueue sind, verwenden Sie dies einfach als internen Datentyp, und Sie sollten eine flexible Implementierung haben, die praktisch in kürzester Zeit ausgeführt werden kann :-)
AKTUALISIEREN:
Wie unten beschrieben, stehen zwei offene Implementierungen zur Verfügung (diese Antwort ist ziemlich alt, Leute!). Weitere Informationen finden Sie in dieser Antwort .
Verwenden Sie Queue anstelle von AbstractQueue. Möglicherweise gibt es Warteschlangen, die die Schnittstelle implementieren, die abstrakte Klasse jedoch nicht erweitern.
TofuBeer
1
In Python können Sie ein collection.dequemit einem angegebenen verwenden maxlen.
Jonas Gröger
2
UPDATE Es stehen jetzt zwei solcher Klassen zur Verfügung. Sie müssen keine eigenen schreiben. Siehe meine Antwort auf dieser Seite.
Basil Bourque
107
Eigentlich macht die LinkedHashMap genau das, was Sie wollen. Sie müssen die removeEldestEntryMethode überschreiben .
Beispiel für eine Warteschlange mit maximal 10 Elementen:
@ user7294900 Danke, Link behoben. Zu Ihrer Information, Stack Overflow lädt Sie ein, solche Änderungen direkt an einer Antwort selbst vorzunehmen. Jeder kann bearbeiten, nicht nur der ursprüngliche Autor. Der Stapelüberlauf soll in dieser Hinsicht eher Wikipedia ähneln.
Basil Bourque
@BasilBourque ja, aber solche Änderungen können auch von mir abgelehnt werden , wenn Links zu ändern , es ist ein Graubereich
user7294900
18
Ich habe gerade eine Warteschlange mit fester Größe folgendermaßen implementiert:
publicclassLimitedSizeQueue<K>extendsArrayList<K>{privateint maxSize;publicLimitedSizeQueue(int size){this.maxSize = size;}publicboolean 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);}}
Ich stimme Amhed oben zu. Entfernen Sie die - 1. Andernfalls erhalten Sie bei maximaler Kapazität ein Array mit maxSize + 1, da es sich um 0 handelt. Zum Beispiel. Wenn maxSize = 50 ist, lautet die removeRange-Formel im ursprünglichen Beitrag beim Hinzufügen eines neuen Objekts 51 - 50 - 1 = 0 (dh nichts entfernt).
Etep
8
Dies ist, was ich mit Queueeingewickelt gemacht habe LinkedList. Es hat eine feste Größe, die ich hier gebe, ist 2;
publicstaticQueue<String> pageQueue;
pageQueue =newLinkedList<String>(){privatestaticfinallong serialVersionUID =-6707803882461262867L;publicboolean 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");.....
Diese Klasse erledigt die Arbeit mit Komposition anstelle von Vererbung (andere Antworten hier), wodurch die Möglichkeit bestimmter Nebenwirkungen ausgeschlossen wird (wie von Josh Bloch in Essential Java behandelt). Das Trimmen der zugrunde liegenden LinkedList erfolgt für die Methoden add, addAll und angeboten.
Tatsächlich müsste er das erste Element löschen (dh frühestens), das Abschneiden würde das letzte Element entfernen. Immer noch praktisch mit einer LinkedList.
Es ist nicht ganz klar, welche Anforderungen Sie dazu veranlasst haben, diese Frage zu stellen. Wenn Sie eine Datenstruktur mit fester Größe benötigen, sollten Sie sich auch verschiedene Caching-Richtlinien ansehen. Da Sie jedoch eine Warteschlange haben, ist meine beste Vermutung, dass Sie nach einer Art Router-Funktionalität suchen. In diesem Fall würde ich einen Ringpuffer verwenden: ein Array mit einem ersten und einem letzten Index. Wenn ein Element hinzugefügt wird, erhöhen Sie einfach den letzten Elementindex. Wenn ein Element entfernt wird, erhöhen Sie den ersten Elementindex. In beiden Fällen erfolgt das Hinzufügen modulo der Arraygröße, und stellen Sie sicher, dass der andere Index bei Bedarf erhöht wird, dh wenn die Warteschlange voll oder leer ist.
Wenn es sich um eine Anwendung vom Typ Router handelt, können Sie auch mit einem Algorithmus wie Random Early Dropping (RED) experimentieren, mit dem Elemente zufällig aus der Warteschlange entfernt werden, noch bevor sie voll sind. In einigen Fällen wurde festgestellt, dass RED eine bessere Gesamtleistung aufweist als die einfache Methode, mit der die Warteschlange vor dem Löschen gefüllt werden kann.
Eigentlich können Sie Ihr eigenes Impl basierend auf LinkedList schreiben, es ist ganz einfach, überschreiben Sie einfach die Add-Methode und erledigen Sie die Mitarbeiter.
Antworten:
In Java Language und Runtime ist keine Implementierung vorhanden. Alle Warteschlangen erweitern AbstractQueue , und in seinem Dokument wird eindeutig angegeben, dass das Hinzufügen eines Elements zu einer vollständigen Warteschlange immer mit einer Ausnahme endet. Es ist am besten (und ganz einfach), eine Warteschlange in eine eigene Klasse zu packen, um die Funktionalität zu erhalten, die Sie benötigen.
Da alle Warteschlangen untergeordnete Elemente von AbstractQueue sind, verwenden Sie dies einfach als internen Datentyp, und Sie sollten eine flexible Implementierung haben, die praktisch in kürzester Zeit ausgeführt werden kann :-)
AKTUALISIEREN:
Wie unten beschrieben, stehen zwei offene Implementierungen zur Verfügung (diese Antwort ist ziemlich alt, Leute!). Weitere Informationen finden Sie in dieser Antwort .
quelle
collection.deque
mit einem angegebenen verwendenmaxlen
.Eigentlich macht die LinkedHashMap genau das, was Sie wollen. Sie müssen die
removeEldestEntry
Methode überschreiben .Beispiel für eine Warteschlange mit maximal 10 Elementen:
Wenn "removeEldestEntry" true zurückgibt, wird der älteste Eintrag aus der Karte entfernt.
quelle
Ja, zwei
Aus meiner eigenen doppelten Frage mit dieser richtigen Antwort habe ich zwei gelernt:
EvictingQueue
in Google GuavaCircularFifoQueue
in Apache CommonsIch habe die Guave produktiv genutzt
EvictingQueue
und gut gearbeitet.Um einen
EvictingQueue
Anruf zu instanziieren, rufen Sie die statische Factory-Methode aufcreate
und geben Sie Ihre maximale Größe an.quelle
CircularFifoQueue
Link ist tot, verwenden Sie stattdessen commons.apache.org/proper/commons-collections/apidocs/org/…Ich habe gerade eine Warteschlange mit fester Größe folgendermaßen implementiert:
quelle
removeRange(0, size() - maxSize)
Dies ist, was ich mit
Queue
eingewickelt gemacht habeLinkedList
. Es hat eine feste Größe, die ich hier gebe, ist 2;quelle
Ich denke, was Sie beschreiben, ist eine kreisförmige Warteschlange. Hier ist ein Beispiel , und hier ist ein besser ein
quelle
Diese Klasse erledigt die Arbeit mit Komposition anstelle von Vererbung (andere Antworten hier), wodurch die Möglichkeit bestimmter Nebenwirkungen ausgeschlossen wird (wie von Josh Bloch in Essential Java behandelt). Das Trimmen der zugrunde liegenden LinkedList erfolgt für die Methoden add, addAll und angeboten.
quelle
Verwendung und Testergebnis:
quelle
Klingt wie eine normale Liste, in der die Methode add ein zusätzliches Snippet enthält, das die Liste abschneidet, wenn sie zu lang wird.
Wenn das zu einfach ist, müssen Sie wahrscheinlich Ihre Problembeschreibung bearbeiten.
quelle
Siehe auch diese SO-Frage oder ArrayBlockingQueue (Vorsicht beim Blockieren, dies kann in Ihrem Fall unerwünscht sein).
quelle
Es ist nicht ganz klar, welche Anforderungen Sie dazu veranlasst haben, diese Frage zu stellen. Wenn Sie eine Datenstruktur mit fester Größe benötigen, sollten Sie sich auch verschiedene Caching-Richtlinien ansehen. Da Sie jedoch eine Warteschlange haben, ist meine beste Vermutung, dass Sie nach einer Art Router-Funktionalität suchen. In diesem Fall würde ich einen Ringpuffer verwenden: ein Array mit einem ersten und einem letzten Index. Wenn ein Element hinzugefügt wird, erhöhen Sie einfach den letzten Elementindex. Wenn ein Element entfernt wird, erhöhen Sie den ersten Elementindex. In beiden Fällen erfolgt das Hinzufügen modulo der Arraygröße, und stellen Sie sicher, dass der andere Index bei Bedarf erhöht wird, dh wenn die Warteschlange voll oder leer ist.
Wenn es sich um eine Anwendung vom Typ Router handelt, können Sie auch mit einem Algorithmus wie Random Early Dropping (RED) experimentieren, mit dem Elemente zufällig aus der Warteschlange entfernt werden, noch bevor sie voll sind. In einigen Fällen wurde festgestellt, dass RED eine bessere Gesamtleistung aufweist als die einfache Methode, mit der die Warteschlange vor dem Löschen gefüllt werden kann.
quelle
Eigentlich können Sie Ihr eigenes Impl basierend auf LinkedList schreiben, es ist ganz einfach, überschreiben Sie einfach die Add-Methode und erledigen Sie die Mitarbeiter.
quelle
Ich denke, die am besten passende Antwort stammt von dieser anderen Frage .
Apache Commons Collections 4 verfügt über eine CircularFifoQueue, nach der Sie suchen. Javadoc zitieren:
quelle
Eine einfache Lösung, unten ist eine Warteschlange von "String"
Beachten Sie, dass dadurch die Reihenfolge der Elemente in der Warteschlange nicht beibehalten wird, sondern der älteste Eintrag ersetzt wird.
quelle
Wie in OOPs empfohlen, sollten wir die Komposition der Vererbung vorziehen
Hier meine Lösung, die das berücksichtigt.
quelle