Zusammenfassung ArrayList
mit ArrayDeque
sind in viel mehr Anwendungsfällen vorzuziehen als LinkedList
. Wenn Sie sich nicht sicher sind, beginnen Sie einfach mit ArrayList
.
LinkedList
und ArrayList
sind zwei verschiedene Implementierungen der List-Schnittstelle. LinkedList
implementiert es mit einer doppelt verknüpften Liste. ArrayList
implementiert es mit einem Array mit dynamischer Größenänderung.
Wie bei Standardoperationen für verknüpfte Listen und Arrays haben die verschiedenen Methoden unterschiedliche algorithmische Laufzeiten.
Zum LinkedList<E>
get(int index)
ist O (n) (mit durchschnittlich n / 4 Schritten), aber O (1) wann index = 0
oder index = list.size() - 1
(in diesem Fall können Sie auch getFirst()
und verwenden getLast()
). Einer der Hauptvorteile von LinkedList<E>
add(int index, E element)
ist O (n) (mit durchschnittlich n / 4 Schritten), aber O (1) wann index = 0
oder index = list.size() - 1
(in diesem Fall können Sie auch addFirst()
und addLast()
/ add()
) verwenden. Einer der Hauptvorteile von LinkedList<E>
remove(int index)
ist O (n) (mit durchschnittlich n / 4 Schritten), aber O (1) wann index = 0
oder index = list.size() - 1
(in diesem Fall können Sie auch removeFirst()
und verwenden removeLast()
). Einer der Hauptvorteile von LinkedList<E>
Iterator.remove()
ist O (1) . Einer der Hauptvorteile von LinkedList<E>
ListIterator.add(E element)
ist O (1) . Einer der Hauptvorteile von LinkedList<E>
Hinweis: Viele der Operationen benötigen durchschnittlich n / 4 Schritte, im besten Fall eine konstante Anzahl von Schritten (z. B. Index = 0) und im schlechtesten Fall (Mitte der Liste) n / 2 Schritte.
Zum ArrayList<E>
get(int index)
ist O (1) . Hauptvorteil von ArrayList<E>
add(E element)
ist O (1) amortisiert, aber O (n) im schlimmsten Fall, da die Größe des Arrays geändert und kopiert werden muss
add(int index, E element)
ist O (n) (mit durchschnittlich n / 2 Schritten)
remove(int index)
ist O (n) (mit durchschnittlich n / 2 Schritten)
Iterator.remove()
ist O (n) (mit durchschnittlich n / 2 Schritten)
ListIterator.add(E element)
ist O (n) (mit durchschnittlich n / 2 Schritten)
Hinweis: Viele der Operationen benötigen durchschnittlich n / 2 Schritte, im besten Fall eine konstante Anzahl von Schritten (Ende der Liste), im schlechtesten Fall n Schritte (Beginn der Liste)
LinkedList<E>
Ermöglicht zeitlich konstante Einfügungen oder Entfernungen mithilfe von Iteratoren , jedoch nur den sequentiellen Zugriff auf Elemente. Mit anderen Worten, Sie können die Liste vorwärts oder rückwärts gehen, aber das Finden einer Position in der Liste benötigt Zeit, die proportional zur Größe der Liste ist. Javadoc sagt, "Operationen, die in die Liste indizieren, durchlaufen die Liste vom Anfang oder vom Ende, je nachdem, was näher liegt" , so dass diese Methoden im Durchschnitt O (n) ( n / 4 Schritte) sind, obwohl O (1) für index = 0
.
ArrayList<E>
Ermöglichen Sie andererseits einen schnellen zufälligen Lesezugriff, sodass Sie jedes Element in konstanter Zeit erfassen können. Das Hinzufügen oder Entfernen von einer anderen Stelle als dem Ende erfordert jedoch das Verschieben aller letzteren Elemente, um entweder eine Öffnung herzustellen oder die Lücke zu füllen. Auch, wenn Sie mehr Elemente als die Kapazität des zugrunde liegenden Array hinzufügen, wird ein neues Array ( die 1,5 - fache der Größe) zugeordnet, und die alte Array wird auf den neuen kopiert, wenn man so eine Zugabe ArrayList
ist O (n) im schlechtesten Fall aber im Durchschnitt konstant.
Abhängig von den geplanten Vorgängen sollten Sie die Implementierungen entsprechend auswählen. Das Iterieren über jede Art von Liste ist praktisch gleich billig. (Das Iterieren über ein ArrayList
ist technisch schneller, aber wenn Sie nicht etwas wirklich Leistungsempfindliches tun, sollten Sie sich darüber keine Sorgen machen - beide sind Konstanten.)
Die Hauptvorteile der Verwendung von a LinkedList
ergeben sich, wenn Sie vorhandene Iteratoren zum Einfügen und Entfernen von Elementen wiederverwenden. Diese Operationen können dann in O (1) ausgeführt werden, indem die Liste nur lokal geändert wird. In einer Array-Liste muss der Rest des Arrays verschoben (dh kopiert) werden. Auf der anderen Seite kann in einem LinkedList
Mittel nach den Verknüpfungen in O (n) ( n / 2 Schritte) nach dem schlimmsten Fall gesucht werden, während in einer ArrayList
gewünschten Position mathematisch berechnet und in O (1) zugegriffen werden kann .
Ein weiterer Vorteil der Verwendung von a LinkedList
ergibt sich, wenn Sie den Kopf der Liste hinzufügen oder daraus entfernen, da diese Operationen O (1) sind , während sie O (n) für sind ArrayList
. Beachten Sie, dass ArrayDeque
dies eine gute Alternative zum LinkedList
Hinzufügen und Entfernen vom Kopf sein kann, aber keine List
.
Wenn Sie große Listen haben, beachten Sie auch, dass die Speichernutzung ebenfalls unterschiedlich ist. Jedes Element von a LinkedList
hat mehr Overhead, da auch Zeiger auf das nächste und das vorherige Element gespeichert werden. ArrayLists
habe diesen Overhead nicht. Allerdings ArrayLists
nehmen so viel Speicher wie oben für die Kapazität zugeordnet ist, unabhängig davon , ob Elemente tatsächlich hinzugefügt.
Die Standard-Anfangskapazität von a ArrayList
ist ziemlich klein (10 von Java 1.4 - 1.8). Da es sich bei der zugrunde liegenden Implementierung jedoch um ein Array handelt, muss die Größe des Arrays geändert werden, wenn Sie viele Elemente hinzufügen. Um die hohen Kosten für die Größenänderung zu vermeiden, wenn Sie wissen, dass Sie viele Elemente hinzufügen werden, erstellen Sie die ArrayList
mit einer höheren Anfangskapazität.