Was ist die schnellste Java-Sammlung mit der Grundfunktionalität einer Warteschlange?

75

Was ist die schnellste Sammlung in Java?

Ich brauche nur die Operationen zum Hinzufügen und Entfernen, die Reihenfolge ist nicht wichtig, gleich Elemente sind kein Problem, nichts anderes als Hinzufügen und Entfernen ist wichtig.

Ohne Begrenzung ist auch die Größe wichtig.

Diese Sammlung enthält Objekte in ihm.

Derzeit verwende ich ArrayDeque, da ich sehe, dass dies die schnellere Queue-Implementierung ist.

Renato Dinhani
quelle
10
Wenn die Reihenfolge nicht wichtig ist, suchen Sie keine Warteschlange.
BoltClock
Momentan füge ich das Finale hinzu und rufe von Anfang an ab (wie eine Warteschlange), aber wenn ich alle Elemente einzeln herausnehmen kann, kann ich eine andere Sammlung verwenden.
Renato Dinhani
3
"... vorzeitige Optimierung ist die Wurzel allen Übels"
mre
56
Die Auswahl der richtigen Kollektion ist keine vorzeitige Optimierung.
Bozho
7
BoltClock, das ist für eine Capital-Q-Warteschlange in Java falsch. Es bedeutet nur "eine veränderbare Sammlung mit einem Kopfelement". Lesen Sie java.util.Queue erneut.
Kevin Bourrillion

Antworten:

95

ArrayDequeist das Beste. Sehen Sie sich diesen Benchmark an , der aus diesem Blog-Beitrag über die Ergebnisse des Benchmarking stammt. ArrayDequeEs gibt weder den Overhead für Knotenzuweisungen LinkedListnoch den Overhead für die Verschiebung des Array-Inhalts, der beim Entfernen übrig bleibt ArrayList. Im Benchmark ist die Leistung etwa dreimal so hoch wie LinkedListbei großen Warteschlangen und sogar etwas besser als ArrayListbei leeren Warteschlangen. Um die beste Leistung zu erzielen, sollten Sie ihm eine Anfangskapazität geben, die groß genug ist, um die Anzahl der Elemente zu speichern, die wahrscheinlich gleichzeitig gespeichert werden, um viele Größenänderungen zu vermeiden.

Zwischen ArrayListund LinkedList, so scheint es , dass es auf der durchschnittlichen Anzahl der Gesamt Elemente hängt die Warteschlange zu einem bestimmten Zeitpunkt enthält und dass LinkedListSchläge ArrayListbei etwa 10 Elementen beginnen.

ColinD
quelle
Die als Stapel verwendete ArrayList sollte mit ArrayDeque identisch sein. Die anfängliche Kapazität wirkt sich stark auf die Leistung aus. Zu viel bedeutet mehr Speicher zum Zuweisen und Sammeln, zu wenig bedeutet mehr Kopien (aber imo ist es insgesamt besser als zu groß für enge Schleifen). Ich konnte die Quelle des Benchmarks nicht sehen. Ist er verfügbar?
Bests
@bestsss: Ja, die Verwendung als Stapel ArrayListwäre ungefähr gleichwertig, obwohl ArrayDequeJavadoc darauf hinweist, dass es möglicherweise etwas schneller ist. Und ja, angesichts der Anforderungen in der Frage würde eine stapelartige Verwendung gut funktionieren. Der Benchmark war jedoch speziell für die Verwendung in der FIFO-Warteschlange vorgesehen (ein Beispiel für den Code finden Sie im verlinkten Blog-Beitrag).
ColinD
7
Mir ist klar, dass diese Frage alt ist, aber Ihre beiden Links sind tot. Gibt es alternative URLs?
Rath
4
Da ich das gleiche Problem wie @rath hatte, habe ich den ursprünglichen Blog gecrawlt und den ursprünglichen Artikel gefunden: https://publicobject.com/2010/07/07/caliper_confirms_reality_linked_list_vs_array_list/ . Wenn ich versuche, die Benchmark-Ergebnisse anzuzeigen, wird leider ein 401 - nicht autorisierter Fehler angezeigt.
Ocramot
3
Hier ist auch ein weiteres Experiment, das bestätigt, dass ArrayDeque 3x schneller als LinkedList ist: java-performance.info/linkedlist-performance
Dheeru Mundluru
6

Sie können a verwenden java.util.LinkedList- es ist doppelt verknüpft und cicrular, also ist das Hinzufügen zu einem Ende und das Nehmen vom anderen O (1)

Egal für welche Implementierung Sie sich entscheiden, beziehen Sie sich auf die QueueBenutzeroberfläche, damit Sie sie leicht ändern können, wenn sich herausstellt, dass sie nicht zu Ihrem Fall passt (wenn Sie natürlich zuerst eine Warteschlange benötigen).

Update: Colins Antwort zeigt einen Benchmark, der zu dem Schluss kommt, dass dies ArrayDequebesser ist. Beide haben O (1) -Operationen, LinkedListerstellen jedoch neue Objekte (Knoten), die die Leistung geringfügig verbessern. Da beide O (1) haben, denke ich nicht, dass es zu falsch wäre, eine Wahl zu LinkedListtreffen.

Bozho
quelle
2
ArrayDequeist objektiv besser.
ColinD
@ColinD - Ich habe gesehen, aber warum? Aufgrund der Objekterstellung (Knoten) in der linekdlist? Beide scheinen O (1)
Bozho
1
@ColinD @Bozho Die Größe des Arrays in ArrayDeque wird ebenfalls geändert. Die eigentliche Überlegung hierbei ist die algorithmische Komplexität. Alles, was ein Array betrifft, ist O (N) zum Hinzufügen / Löschen, alles, was Links betrifft, ist O (1).
Marquis von Lorne
15
@EJP: ArrayDeque ist O (1) zum Hinzufügen und Entfernen am Front / End (dh bei Verwendung als Warteschlange oder Stapel), da es sich um ein kreisförmiges Array handelt und in diesen Fällen nichts kopiert. Darüber hinaus ist die Größenänderung eine gelegentliche Operation, die häufig mit einer geeigneten Anfangskapazität vermieden werden kann. LinkedListDer Aufwand für eine zusätzliche Objekterstellung (plus Speicherbereinigung dieses Objekts) wirkt sich auf jedes Hinzufügen / Entfernen in der Warteschlange aus. Der von mir verknüpfte Benchmark zeigt, dass er konstant dreimal so schnell ist wie ein LinkedList.
ColinD
1
O(1) != O(1). O()ist nur ein Maß für die Komplexität, nicht für die Ausführungszeit. Eine Operation, die unabhängig davon immer 5 Jahre dauert, nist O(1)ebenso wie eine Operation, die immer 5 ms dauert. Ich würde lieber die verwenden, die 5 ms dauert. Sogar eine Operation, die 5 ms pro Element dauert (was ist O(n)), ist besser als die 5-Jahres-Operation, wenn nsie nicht zu groß wird.
Erick G. Hagstrom
0

ConcurrentLinkedDeque ist die beste Wahl für Multi-Thread-Warteschlangen

Geker
quelle