Ich benötige eine Stack
Datenstruktur für meinen Anwendungsfall. Ich sollte in der Lage sein, Elemente in die Datenstruktur zu verschieben, und ich möchte nur das letzte Element aus dem Stapel abrufen. Das JavaDoc für Stack sagt:
Ein vollständigerer und konsistenterer Satz von LIFO-Stapeloperationen wird von der Deque-Schnittstelle und ihren Implementierungen bereitgestellt, die dieser Klasse vorgezogen werden sollten. Beispielsweise:
Deque<Integer> stack = new ArrayDeque<>();
Ich möchte hier definitiv kein synchronisiertes Verhalten, da ich diese Datenstruktur lokal für eine Methode verwenden werde. Abgesehen davon , warum sollte ich es vorziehen , Deque
über Stack
hier?
PS: Der Javadoc von Deque sagt:
Deques können auch als LIFO-Stapel (Last-In-First-Out) verwendet werden. Diese Schnittstelle sollte der älteren Stack-Klasse vorgezogen werden.
quelle
Antworten:
Zum einen ist es in Bezug auf die Vererbung sinnvoller. Die Tatsache, die
Stack
sichVector
ausdehnt, ist meiner Ansicht nach wirklich seltsam. Zu Beginn von Java wurde die Vererbung IMO überbeansprucht -Properties
ein weiteres Beispiel.Für mich ist das entscheidende Wort in den von Ihnen zitierten Dokumenten konsistent .
Deque
macht eine Reihe von Operationen verfügbar, bei denen es darum geht, Elemente vom Anfang oder Ende einer Sammlung abzurufen, hinzuzufügen oder zu entfernen, zu iterieren usw. - und das war's. Es gibt absichtlich keine Möglichkeit, auf ein Element nach Position zuzugreifen, wodurch esStack
verfügbar gemacht wird, da es sich um eine Unterklasse von handeltVector
.Oh, und
Stack
hat auch keine Schnittstelle. Wenn Sie also wissen, dass SieStack
Operationen benötigen, müssen Sie sich auf eine bestimmte konkrete Klasse festlegen, was normalerweise keine gute Idee ist.Auch wie in den Kommentaren erwähnt,
Stack
undDeque
haben umgekehrte Iterationsreihenfolgen:Dies wird auch in den JavaDocs für Deque.iterator () erläutert :
quelle
LinkedList
, aberArrayDequeue
werden (oft) schneller sein. Wenn Sie ein Stapelverhalten wünschen, können Sie es verwendenStack
, esArrayDeque
wird jedoch (häufig) schneller sein.Stack
sie das Problem der Wiederholungsbelichtung hat, aber wenn ich eine Stack-Datenstruktur möchte, möchte ich Methoden wie Push, Pop und Peek aufrufen können und nicht Dinge, die es müssen mache mit dem anderen Ende des Stapels.Hier ist meine Interpretation der Inkonsistenz, die in der Beschreibung der Stapelklasse erwähnt wird.
Wenn Sie sich hier Allzweckimplementierungen ansehen, werden Sie feststellen, dass es einen konsistenten Ansatz für die Implementierung von Set, Map und List gibt.
Für Set und Map haben wir 2 Standardimplementierungen mit Hash-Maps und Bäumen. Die erste wird am häufigsten verwendet und die zweite wird verwendet, wenn wir eine geordnete Struktur benötigen (und sie implementiert auch eine eigene Schnittstelle - SortedSet oder SortedMap).
Wir können den bevorzugten Deklarationsstil verwenden, wie hier
Set<String> set = new HashSet<String>();
Gründe zu sehen .Aber Stack-Klasse: 1) haben keine eigene Schnittstelle; 2) ist eine Unterklasse der Vektorklasse - die auf einem anpassbaren Array basiert; Wo ist also die Implementierung der verknüpften Liste des Stapels?
In der Deque-Schnittstelle gibt es keine derartigen Probleme, einschließlich zweier Implementierungen (anpassbares Array - ArrayDeque; verknüpfte Liste - LinkedList).
quelle
Ein weiterer Grund für die Verwendung von Dequeue over Stack ist, dass Dequeue Streams verwenden kann, die in Listen konvertiert werden, wobei das LIFO-Konzept angewendet wird, während Stack dies nicht tut.
quelle
Hier sind einige Gründe, warum Deque besser ist als Stack:
Objektorientiertes Design - Vererbung, Abstraktion, Klassen und Schnittstellen: Stack ist eine Klasse, Deque ist eine Schnittstelle. Es kann nur eine Klasse erweitert werden, während eine beliebige Anzahl von Schnittstellen von einer einzelnen Klasse in Java implementiert werden kann (Mehrfachvererbung des Typs). Durch die Verwendung der Deque-Schnittstelle wird die Abhängigkeit von der konkreten Stack-Klasse und ihren Vorfahren aufgehoben und Sie erhalten mehr Flexibilität, z. B. die Freiheit, eine andere Klasse zu erweitern oder verschiedene Implementierungen von Deque (wie LinkedList, ArrayDeque) auszutauschen.
Inkonsistenz: Stack erweitert die Vector-Klasse, mit der Sie über den Index auf Elemente zugreifen können. Dies steht im Widerspruch zu dem, was ein Stack tatsächlich tun sollte, weshalb die Deque-Schnittstelle bevorzugt wird (solche Operationen sind nicht zulässig). Die zulässigen Operationen stimmen mit den Anforderungen einer FIFO- oder LIFO-Datenstruktur überein.
Leistung: Die von Stack erweiterte Vector-Klasse ist im Grunde die "thread-sichere" Version einer ArrayList. Die Synchronisierungen können möglicherweise zu erheblichen Leistungseinbußen für Ihre Anwendung führen. Wenn Sie andere Klassen mit nicht benötigten Funktionen erweitern (wie in Nr. 2 erwähnt), werden Ihre Objekte aufgebläht, was möglicherweise viel zusätzlichen Speicher und Leistungsaufwand kostet.
quelle
Für mich fehlte dieser spezielle Punkt: Stack ist Threadsafe, da es von Vector abgeleitet ist, während die meisten Deque-Implementierungen dies nicht tun, und daher schneller, wenn Sie es nur in einem einzelnen Thread verwenden.
quelle
Leistung könnte ein Grund sein. Ein von mir verwendeter Algorithmus ging von 7,6 Minuten auf 1,5 Minuten zurück, indem nur Stack durch Deque ersetzt wurde.
quelle
Deque wird verwendet, wenn Sie Elemente sowohl vom Kopf als auch vom Schwanz abrufen möchten. Wenn Sie einen einfachen Stapel wünschen, müssen Sie sich nicht für eine Deque entscheiden.
quelle