it-swarm.com.de

Wann wird LinkedList über ArrayList in Java verwendet?

Ich war schon immer einer, der einfach gebraucht:

List<String> names = new ArrayList<>();

Ich benutze die Schnittstelle als Typname für portability, damit ich meinen Code überarbeiten kann, wenn ich Fragen wie diese gestellt habe. 

Wann sollte LinkedList über ArrayList verwendet werden und umgekehrt?

2750
sdellysse

Zusammenfassung ArrayList mit ArrayDeque sind in vielen weiteren 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, dessen Größe dynamisch geändert wird.

Wie bei Standardoperationen für verknüpfte Listen und Arrays weisen die verschiedenen Methoden unterschiedliche algorithmische Laufzeiten auf.

Für LinkedList<E>

  • get(int index) ist O (n) (mit n/4 Schritten im Durchschnitt)
  • add(E element) ist O (1)
  • add(int index, E element) ist O (n) (mit n/4 Schritten im Durchschnitt), aber O (1) wenn _index = 0_ <--- Hauptvorteil von _LinkedList<E>_
  • remove(int index) ist O (n) (mit n/4 Schritten im Durchschnitt)
  • Iterator.remove() ist O (1) . <--- Hauptvorteil von _LinkedList<E>_
  • ListIterator.add(E element) is O (1) Dies ist einer der Hauptvorteile von _LinkedList<E>_

Hinweis: Viele Operationen benötigen n/4 Schritte im Durchschnitt, konstante Anzahl von Schritten im besten Fall (z. B. index =) 0) und n/2 Schritte im ungünstigsten Fall (Mitte der Liste)

Für ArrayList<E>

  • get(int index) ist O (1) <--- Hauptvorteil von _ArrayList<E>_
  • add(E element) ist O (1) amortisiert, aber O (n) im ungünstigsten Fall, da die Größe des Arrays geändert werden muss und kopiert
  • add(int index, E element) ist O (n) (mit n/2 Schritten im Durchschnitt)
  • remove(int index) ist O (n) (mit n/2 Schritten im Durchschnitt)
  • Iterator.remove() ist O (n) (mit n/2 Schritten im Durchschnitt)
  • ListIterator.add(E element) ist O (n) (mit n/2 Schritten im Durchschnitt)

Hinweis: Viele Operationen benötigen n/2 Schritte im Durchschnitt, konstante Anzahl von Schritten im besten Fall (Ende der Liste) ), n Schritte im ungünstigsten Fall (Listenanfang)

_LinkedList<E>_ ermöglicht zeitlich konstante Einfügungen oder Entfernungen unter Verwendung von Iteratoren , jedoch nur einen sequentiellen Zugriff auf Elemente. Mit anderen Worten, Sie können die Liste vorwärts oder rückwärts durchgehen, 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 Ende, je nachdem, was näher liegt" , so dass diese Methoden O ( n) ( n/4 Schritte) im Durchschnitt, obwohl O (1) für _index = 0_.

_ArrayList<E>_ hingegen ermöglicht einen schnellen wahlfreien Lesezugriff, sodass Sie jedes Element in konstanter Zeit erfassen können. Das Hinzufügen oder Entfernen an einer anderen Stelle als am Ende erfordert jedoch das Verschieben aller letzteren Elemente, um entweder eine Öffnung zu schaffen oder die Lücke zu füllen. Wenn Sie mehr Elemente als die Kapazität des zugrunde liegenden Arrays hinzufügen, wird ein neues Array (1,5-fache Größe) zugewiesen, und das alte Array wird in das neue Array kopiert. Das Hinzufügen zu einem ArrayList ist also O (n) im schlimmsten Fall aber im Durchschnitt konstant.

Abhängig von den Operationen, die Sie ausführen möchten, sollten Sie die Implementierungen entsprechend auswählen. Das Durchlaufen einer Liste ist praktisch gleich günstig. (Das Durchlaufen eines ArrayList ist technisch gesehen schneller, aber Sie sollten sich darüber keine Gedanken machen, es sei denn, Sie sind wirklich leistungsabhängig. Sie sind beide Konstanten.)

Die Hauptvorteile der Verwendung von LinkedList ergeben sich, wenn Sie vorhandene Iteratoren wiederverwenden, um Elemente einzufügen und zu entfernen. 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 (d. H. Kopiert) werden. Auf der anderen Seite bedeutet das Suchen in einem LinkedList, den Links in O (n) ( n/2 zu folgen. Schritte) für den ungünstigsten Fall, während in ArrayList die gewünschte Position mathematisch berechnet und in O (1) abgerufen werden kann.

Ein weiterer Vorteil der Verwendung von LinkedList ergibt sich, wenn Sie dem Kopf der Liste hinzufügen oder daraus entfernen, da diese Operationen O (1) sind, während sie O (n) für ArrayList. Beachten Sie, dass ArrayDeque möglicherweise eine gute Alternative zu LinkedList zum Hinzufügen und Entfernen vom Kopf ist, aber es ist kein List.

Beachten Sie bei umfangreichen Listen auch, dass sich die Speichernutzung unterscheidet. Jedes Element eines LinkedList hat mehr Overhead, da auch Zeiger auf das nächste und vorherige Element gespeichert werden. ArrayLists haben diesen Aufwand nicht. ArrayLists belegt jedoch so viel Speicher, wie für die Kapazität reserviert ist, unabhängig davon, ob tatsächlich Elemente hinzugefügt wurden.

Die Standard-Anfangskapazität eines ArrayList ist ziemlich klein (10 von Java 1.4 - 1.8). Da es sich bei der zugrunde liegenden Implementierung um ein Array handelt, muss die Größe des Arrays geändert werden, wenn Sie viele Elemente hinzufügen. Konstruieren Sie ArrayList mit einer höheren Anfangskapazität, um die hohen Kosten für die Größenänderung zu vermeiden, wenn Sie wissen, dass Sie viele Elemente hinzufügen werden.

3177
Jonathan Tran

Bisher scheint sich niemand mit dem Speicherbedarf jeder dieser Listen befasst zu haben, außer dem allgemeinen Konsens, dass ein LinkedList "viel mehr" ist als ein ArrayList, also habe ich einige Zahlen gezählt, um genau zu zeigen, wie viel beide Listen nehmen für N Nullreferenzen auf.

Da Referenzen auf ihren jeweiligen Systemen entweder 32 oder 64 Bit (selbst wenn Null) sind, habe ich 4 Datensätze für 32 und 64 Bit LinkedLists und ArrayLists eingefügt.

Hinweis: Die angegebenen Größen für die ArrayList - Zeilen gelten für zugeschnittene Listen - In der Praxis ist die Kapazität der Das Backing-Array in einem ArrayList ist im Allgemeinen größer als die aktuelle Elementanzahl.

Anmerkung 2: (danke BeeOnRope) Da CompressedOops jetzt ab Mitte JDK6 die folgenden Werte für 64-Bit hat Maschinen stimmen im Wesentlichen mit ihren 32-Bit-Gegenstücken überein, es sei denn, Sie schalten sie ausdrücklich aus.


Graph of LinkedList and ArrayList No. of Elements x Bytes


Das Ergebnis zeigt deutlich, dass LinkedList sehr viel mehr ist als ArrayList, insbesondere mit einer sehr hohen Anzahl von Elementen. Wenn das Gedächtnis ein Faktor ist, meiden Sie LinkedLists.

Die verwendeten Formeln folgen, lassen Sie mich wissen, wenn ich etwas falsch gemacht habe und ich werde es beheben. 'b' ist entweder 4 oder 8 für 32- oder 64-Bit-Systeme und 'n' ist die Anzahl der Elemente. Beachten Sie, dass der Grund für die Mods darin besteht, dass alle Objekte in Java ein Vielfaches von 8 Byte Speicherplatz belegen, unabhängig davon, ob sie alle verwendet werden oder nicht.

ArrayList:

ArrayList object header + size integer + modCount integer + array reference + (array oject header + b * n) + MOD(array oject, 8) + MOD(ArrayList object, 8) == 8 + 4 + 4 + b + (12 + b * n) + MOD(12 + b * n, 8) + MOD(8 + 4 + 4 + b + (12 + b * n) + MOD(12 + b * n, 8), 8)

LinkedList:

LinkedList object header + size integer + modCount integer + reference to header + reference to footer + (node object overhead + reference to previous element + reference to next element + reference to element) * n) + MOD(node object, 8) * n + MOD(LinkedList object, 8) == 8 + 4 + 4 + 2 * b + (8 + 3 * b) * n + MOD(8 + 3 * b, 8) * n + MOD(8 + 4 + 4 + 2 * b + (8 + 3 * b) * n + MOD(8 + 3 * b, 8) * n, 8)

598
Numeron

ArrayList ist das, was Sie wollen. LinkedList ist fast immer ein (Performance-) Fehler.

Warum LinkedList saugt:

  • Es verwendet viele kleine Speicherobjekte und beeinflusst daher die Leistung im gesamten Prozess.
  • Viele kleine Objekte sind schlecht für die Cache-Lokalität.
  • Jede indizierte Operation erfordert eine Durchquerung, d. H. Hat eine Leistung von O(n). Dies ist im Quellcode nicht offensichtlich und führt zu langsameren Algorithmen O(n) als bei Verwendung von ArrayList.
  • Gute Leistung zu erhalten ist schwierig.
  • Selbst wenn die Leistung von big-O mit ArrayList identisch ist, wird sie wahrscheinlich sowieso wesentlich langsamer sein.
  • Es ist erschütternd, LinkedList in der Quelle zu sehen, weil es wahrscheinlich die falsche Wahl ist.
217

Als jemand, der seit ungefähr einem Jahrzehnt operatives Performance-Engineering in sehr großen SOA - Web-Services durchführt, würde ich das Verhalten von LinkedList gegenüber ArrayList vorziehen. Der Steady-State-Durchsatz von LinkedList ist zwar schlechter und kann daher dazu führen, dass mehr Hardware gekauft wird. Das Verhalten von ArrayList unter Druck könnte dazu führen, dass Apps in einem Cluster ihre Arrays nahezu synchron ausdehnen und bei großen Arraygrößen zu mangelnder Reaktionsfähigkeit führen in der App und einem Ausfall, während unter Druck, das katastrophale Verhalten ist.

In ähnlicher Weise können Sie mit dem standardmäßigen Durchsatz-Garbage Collector einen besseren Durchsatz in einer App erzielen. Sobald Sie jedoch Java-Apps mit 10-GB-Heaps erhalten, können Sie die App für 25 Sekunden während eines vollständigen GCs schließen, was zu Timeouts und Fehlern in SOA und bläst Ihre SLAs auf, wenn dies zu häufig auftritt. Obwohl der CMS-Collector mehr Ressourcen beansprucht und nicht den gleichen Rohdurchsatz erzielt, ist er eine viel bessere Wahl, da er vorhersehbarer ist und eine geringere Latenz aufweist.

ArrayList ist nur dann eine bessere Wahl für die Leistung, wenn Sie nur den Durchsatz als Leistung bezeichnen und die Latenz ignorieren können. Nach meiner Berufserfahrung kann ich die Worst-Case-Latenz nicht ignorieren.

132
lamont
Algorithm           ArrayList   LinkedList
seek front            O(1)         O(1)
seek back             O(1)         O(1)
seek to index         O(1)         O(N)
insert at front       O(N)         O(1)
insert at back        O(1)         O(1)
insert after an item  O(N)         O(1)

Algorithmen: Big-Oh-Notation

ArrayLists eignen sich für Write-Once-Read-Many oder Appender, aber schlecht für das Hinzufügen/Entfernen von vorne oder in der Mitte.

117
Michael Munsey

Ja, ich weiß, das ist eine alte Frage, aber ich werde meine zwei Cents einbringen:

LinkedList ist fast immer die falsche Wahl, leistungsmäßig. Es gibt einige sehr spezifische Algorithmen, für die eine LinkedList erforderlich ist. Diese sind jedoch sehr, sehr selten und der Algorithmus hängt in der Regel speziell von der Fähigkeit von LinkedList ab, Elemente in der Mitte der Liste relativ schnell einzufügen und zu löschen, wenn Sie dort navigiert sind mit einem ListIterator.

Es gibt einen allgemeinen Anwendungsfall, in dem LinkedList ArrayList übertrifft: der einer Warteschlange. Wenn Ihr Ziel jedoch die Leistung ist, sollten Sie anstelle von LinkedList auch die Verwendung einer ArrayBlockingQueue in Betracht ziehen (wenn Sie im Voraus eine Obergrenze für Ihre Warteschlangengröße festlegen können und es sich leisten können, den gesamten Speicher vorab zuzuordnen) oder diese Implementierung von CircularArrayList . (Ja, es ist aus dem Jahr 2001, daher müssen Sie es generieren, aber ich habe vergleichbare Leistungsverhältnisse zu dem, was gerade in einer aktuellen JVM im Artikel zitiert wurde).

97
Daniel Martin

Es ist eine Frage der Effizienz. LinkedList ist schnell zum Hinzufügen und Löschen von Elementen, aber für den Zugriff auf ein bestimmtes Element ist es langsam. ArrayList ist für den Zugriff auf ein bestimmtes Element schnell, kann jedoch langsam an einem Ende hinzugefügt werden und vor allem langsam in der Mitte gelöscht werden.

Array vs ArrayList vs LinkedList vs Vector geht tiefer, wie Linked List .

55
dgtized

Richtig oder falsch: Bitte führen Sie den Test vor Ort durch und entscheiden Sie selbst!

Bearbeiten/Entfernen ist in LinkedList schneller als ArrayList.

ArrayList, unterstützt von Array, das doppelt so groß sein muss, ist bei Anwendungen mit großem Volumen schlechter.

Unten ist das Ergebnis der Einheitentests für jede Operation. Die Zeiteinstellung erfolgt in Nanosekunden.


Operation                       ArrayList                      LinkedList  

AddAll   (Insert)               101,16719                      2623,29291 

Add      (Insert-Sequentially)  152,46840                      966,62216

Add      (insert-randomly)      36527                          29193

remove   (Delete)               20,56,9095                     20,45,4904

contains (Search)               186,15,704                     189,64,981

Hier ist der Code:

import org.junit.Assert;
import org.junit.Test;

import Java.util.*;

public class ArrayListVsLinkedList {
    private static final int MAX = 500000;
    String[] strings = maxArray();

    ////////////// ADD ALL ////////////////////////////////////////
    @Test
    public void arrayListAddAll() {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);
        List<String> arrayList = new ArrayList<String>(MAX);

        watch.start();
        arrayList.addAll(stringList);
        watch.totalTime("Array List addAll() = ");//101,16719 Nanoseconds
    }

    @Test
    public void linkedListAddAll() throws Exception {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);

        watch.start();
        List<String> linkedList = new LinkedList<String>();
        linkedList.addAll(stringList);
        watch.totalTime("Linked List addAll() = ");  //2623,29291 Nanoseconds
    }

    //Note: ArrayList is 26 time faster here than LinkedList for addAll()

    ///////////////// INSERT /////////////////////////////////////////////
    @Test
    public void arrayListAdd() {
        Watch watch = new Watch();
        List<String> arrayList = new ArrayList<String>(MAX);

        watch.start();
        for (String string : strings)
            arrayList.add(string);
        watch.totalTime("Array List add() = ");//152,46840 Nanoseconds
    }

    @Test
    public void linkedListAdd() {
        Watch watch = new Watch();

        List<String> linkedList = new LinkedList<String>();
        watch.start();
        for (String string : strings)
            linkedList.add(string);
        watch.totalTime("Linked List add() = ");  //966,62216 Nanoseconds
    }

    //Note: ArrayList is 9 times faster than LinkedList for add sequentially

    /////////////////// INSERT IN BETWEEN ///////////////////////////////////////

    @Test
    public void arrayListInsertOne() {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);
        List<String> arrayList = new ArrayList<String>(MAX + MAX / 10);
        arrayList.addAll(stringList);

        String insertString0 = getString(true, MAX / 2 + 10);
        String insertString1 = getString(true, MAX / 2 + 20);
        String insertString2 = getString(true, MAX / 2 + 30);
        String insertString3 = getString(true, MAX / 2 + 40);

        watch.start();

        arrayList.add(insertString0);
        arrayList.add(insertString1);
        arrayList.add(insertString2);
        arrayList.add(insertString3);

        watch.totalTime("Array List add() = ");//36527
    }

    @Test
    public void linkedListInsertOne() {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);
        List<String> linkedList = new LinkedList<String>();
        linkedList.addAll(stringList);

        String insertString0 = getString(true, MAX / 2 + 10);
        String insertString1 = getString(true, MAX / 2 + 20);
        String insertString2 = getString(true, MAX / 2 + 30);
        String insertString3 = getString(true, MAX / 2 + 40);

        watch.start();

        linkedList.add(insertString0);
        linkedList.add(insertString1);
        linkedList.add(insertString2);
        linkedList.add(insertString3);

        watch.totalTime("Linked List add = ");//29193
    }


    //Note: LinkedList is 3000 nanosecond faster than ArrayList for insert randomly.

    ////////////////// DELETE //////////////////////////////////////////////////////
    @Test
    public void arrayListRemove() throws Exception {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);
        List<String> arrayList = new ArrayList<String>(MAX);

        arrayList.addAll(stringList);
        String searchString0 = getString(true, MAX / 2 + 10);
        String searchString1 = getString(true, MAX / 2 + 20);

        watch.start();
        arrayList.remove(searchString0);
        arrayList.remove(searchString1);
        watch.totalTime("Array List remove() = ");//20,56,9095 Nanoseconds
    }

    @Test
    public void linkedListRemove() throws Exception {
        Watch watch = new Watch();
        List<String> linkedList = new LinkedList<String>();
        linkedList.addAll(Arrays.asList(strings));

        String searchString0 = getString(true, MAX / 2 + 10);
        String searchString1 = getString(true, MAX / 2 + 20);

        watch.start();
        linkedList.remove(searchString0);
        linkedList.remove(searchString1);
        watch.totalTime("Linked List remove = ");//20,45,4904 Nanoseconds
    }

    //Note: LinkedList is 10 millisecond faster than ArrayList while removing item.

    ///////////////////// SEARCH ///////////////////////////////////////////
    @Test
    public void arrayListSearch() throws Exception {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);
        List<String> arrayList = new ArrayList<String>(MAX);

        arrayList.addAll(stringList);
        String searchString0 = getString(true, MAX / 2 + 10);
        String searchString1 = getString(true, MAX / 2 + 20);

        watch.start();
        arrayList.contains(searchString0);
        arrayList.contains(searchString1);
        watch.totalTime("Array List addAll() time = ");//186,15,704
    }

    @Test
    public void linkedListSearch() throws Exception {
        Watch watch = new Watch();
        List<String> linkedList = new LinkedList<String>();
        linkedList.addAll(Arrays.asList(strings));

        String searchString0 = getString(true, MAX / 2 + 10);
        String searchString1 = getString(true, MAX / 2 + 20);

        watch.start();
        linkedList.contains(searchString0);
        linkedList.contains(searchString1);
        watch.totalTime("Linked List addAll() time = ");//189,64,981
    }

    //Note: Linked List is 500 Milliseconds faster than ArrayList

    class Watch {
        private long startTime;
        private long endTime;

        public void start() {
            startTime = System.nanoTime();
        }

        private void stop() {
            endTime = System.nanoTime();
        }

        public void totalTime(String s) {
            stop();
            System.out.println(s + (endTime - startTime));
        }
    }


    private String[] maxArray() {
        String[] strings = new String[MAX];
        Boolean result = Boolean.TRUE;
        for (int i = 0; i < MAX; i++) {
            strings[i] = getString(result, i);
            result = !result;
        }
        return strings;
    }

    private String getString(Boolean result, int i) {
        return String.valueOf(result) + i + String.valueOf(!result);
    }
}
52
Ash

ArrayList ist im Wesentlichen ein Array. LinkedList ist als doppelt verknüpfte Liste implementiert. 

Die get ist ziemlich klar. O(1) für ArrayList, da ArrayList den wahlfreien Zugriff über den Index zulässt. O(n) für LinkedList, da zuerst der Index gesucht werden muss. Hinweis: Es gibt verschiedene Versionen von add und remove

LinkedList ist schneller in add und remove, aber langsamer in get. Kurz gesagt, sollte LinkedList bevorzugt werden, wenn: 

  1. es gibt keine große Anzahl von wahlfreiem Zugriff auf element 
  2. es gibt eine große Anzahl von Hinzufügungs-/Entfernungsvorgängen

=== ArrayList ===

  • addiere (E e)
    • add am Ende von ArrayList
    • erfordern die Größenänderung des Speichers. 
    • O (n) am schlechtesten, O(1) amortisiert
  • add (Int-Index, E-Element)
    • zu einer bestimmten Indexposition hinzufügen
    • erfordern Verschiebung und mögliche Kosten für die Größenänderung des Speichers
    • O(n)
  • remove (int index)
    • ein bestimmtes Element entfernen
    • erfordern Verschiebung und mögliche Kosten für die Größenänderung des Speichers
    • O(n)
  • entfernen (Objekt o)
    • entfernen Sie das erste Vorkommen des angegebenen Elements aus dieser Liste
    • zuerst müssen Sie das Element durchsuchen und anschließend die möglichen Kosten für die Größenänderung des Speichers verschieben
    • O(n)

=== LinkedList ===

  • addieren (E e)

    • am Ende der Liste hinzufügen
    • O(1)
  • add (int index, E element)

    • an der angegebenen Position einfügen
    • müssen zuerst die Position finden
    • O(n)
  • löschen()
    • erstes Element der Liste entfernen
    • O(1)
  • remove (int index)
    • element mit dem angegebenen Index entfernen
    • das Element muss zuerst gefunden werden
    • O(n)
  • entfernen (Objekt o)
    • entfernen Sie das erste Vorkommen des angegebenen Elements
    • das Element muss zuerst gefunden werden
    • O(n)

Hier ist eine Abbildung aus programcreek.com (add und remove sind der erste Typ, d. H. Fügen Sie ein Element am Ende der Liste hinzu und entfernen Sie das Element an der angegebenen Position in der Liste.)

enter image description here

44
Ryan

1) Search: Der ArrayList-Suchvorgang ist im Vergleich zum LinkedList-Suchvorgang ziemlich schnell. get (int index) in ArrayList gibt die Leistung von O(1) an, während LinkedList die Leistung O (n) ist.

Reason: ArrayList verwaltet ein indexbasiertes System für seine Elemente, da die Array-Datenstruktur implizit verwendet wird, was die Suche nach einem Element in der Liste beschleunigt. Auf der anderen Seite implementiert LinkedList eine doppelt verknüpfte Liste, die den Durchlauf durch alle Elemente zum Durchsuchen eines Elements erfordert.

2) Deletion: Mit der Operation zum Entfernen von LinkedList wird die Leistung von O(1) erreicht, während mit ArrayList eine variable Leistung erzielt wird: O(n) im schlimmsten Fall (beim Entfernen des ersten Elements) und O(1) im besten Fall (beim Entfernen des letzten Elements).

Fazit: Das Löschen von LinkedList-Elementen ist im Vergleich zu ArrayList schneller.

Reason: Jedes Element von LinkedList enthält zwei Zeiger (Adressen), die auf beide Nachbarelemente in der Liste zeigen. Daher erfordert das Entfernen nur eine Änderung der Zeigerposition in den zwei benachbarten Knoten (Elementen) des Knotens, der entfernt werden soll. In ArrayList müssen alle Elemente verschoben werden, um den durch das entfernte Element erstellten Platz auszufüllen.

3) Inserts Performance: Die LinkedList-Add-Methode gibt O(1) Performance an, während ArrayList O(n) im ungünstigsten Fall ergibt. Der Grund ist derselbe wie für das Entfernen.

4) Memory Overhead: ArrayList verwaltet Indizes und Elementdaten, während LinkedList Elementdaten und zwei Zeiger für benachbarte Knoten verwaltet, sodass der Speicherverbrauch in LinkedList vergleichsweise hoch ist.

Es gibt wenige Ähnlichkeiten zwischen diesen Klassen, die wie folgt lauten:

Sowohl ArrayList als auch LinkedList sind Implementierungen der List-Schnittstelle . Beide behalten die Reihenfolge der Elemente-Einfügung bei, was bedeutet, dass bei der Anzeige von ArrayList- und LinkedList-Elementen die Ergebnismenge dieselbe Reihenfolge hat, in der die Elemente in die Liste ..__ eingefügt wurden. Diese beiden Klassen sind nicht synchronisiert und können mithilfe der Collections.synchronizedList-Methode ..__ explizit synchronisiert werden. Der von diesen Klassen zurückgegebene Iterator und listIterator sind ausfallsicher (wenn die Liste zu irgendeinem Zeitpunkt nach dem Erstellen des Iterators strukturell geändert wird.) Der Iterator löst auf irgendeine Weise außer durch die eigenen Methoden zum Entfernen oder Hinzufügen des Iterators eine ConcurrentModificationException aus.

Wann verwende ich LinkedList und wann verwende ich ArrayList?

1) Wie oben erläutert, ergeben die Einfüge- und Entfernungsoperationen in LinkedList eine gute Leistung (O (1)) im Vergleich zu ArrayList (O (n)). Wenn daher häufiges Hinzufügen und Löschen in einer Anwendung erforderlich ist, ist LinkedList die beste Wahl.

2) Suchoperationen (get-Methode) sind in ArrayList (O (1)) schnell, aber nicht in LinkedList (O (n)). Wenn weniger Add- und Remove-Vorgänge erforderlich sind und mehr Suchvorgänge erforderlich sind, wäre ArrayList die beste Wahl.

35
NoNaMe

Joshua Bloch, der Autor von LinkedList:

Verwendet jemand LinkedList? Ich habe es geschrieben und benutze es nie.

Link: https://Twitter.com/joshbloch/status/583813919019573248

Es tut mir leid für die Antwort, nicht so informativ zu sein wie die anderen Antworten, aber ich dachte, es wäre am interessantesten und selbsterklärend.

33
Ruslan

ArrayList ist nach dem Zufallsprinzip zugänglich, während LinkedList wirklich billig ist, um Elemente zu erweitern und zu entfernen. In den meisten Fällen ist ArrayList in Ordnung.

Wenn Sie keine großen Listen erstellt und einen Engpass gemessen haben, müssen Sie sich wahrscheinlich nie um den Unterschied sorgen.

32
Dustin

Wenn Ihr Code add(0) und remove(0) enthält, verwenden Sie eine LinkedList und die besseren addFirst()- und removeFirst()-Methoden. Andernfalls verwenden Sie ArrayList.

Und natürlich ist Guave 's ImmutableList Ihr bester Freund.

20
Jesse Wilson

Ich weiß, dass dies ein alter Beitrag ist, aber ich kann nicht glauben, dass niemand erwähnt hat, dass LinkedListDeque implementiert. Sehen Sie sich die Methoden in Deque (und Queue) an. Wenn Sie einen fairen Vergleich wünschen, führen Sie LinkedList gegen ArrayDeque aus und führen Sie einen Feature-für-Feature-Vergleich durch. 

20
Ajax

Hier ist die Big-O-Notation in ArrayList und LinkedList und auch CopyOnWrite-ArrayList:

Anordnungsliste

get                 O(1)
add                 O(1)
contains            O(n)
next                O(1)
remove              O(n)
iterator.remove     O(n)

LinkedList

get                 O(n)
add                 O(1)
contains            O(n)
next                O(1)
remove              O(1)
iterator.remove     O(1)

CopyOnWrite-ArrayList

get                 O(1)
add                 O(n)
contains            O(n)
next                O(1)
remove              O(n)
iterator.remove     O(n)

Basierend auf diesen müssen Sie entscheiden, was Sie wählen sollen. :)

18
Rajith Delantha

TL; DR Aufgrund der modernen Computerarchitektur ist ArrayList für nahezu jeden Anwendungsfall wesentlich effizienter - und damit LinkedList sollte mit Ausnahme einiger sehr eindeutiger und extremer Fälle vermieden werden.


Theoretisch hat LinkedList ein O(1) für die add(E element)

Auch das Hinzufügen eines Elements in der Mitte einer Liste sollte sehr effizient sein.

Die Praxis ist sehr unterschiedlich, da LinkedList eine Cache-feindliche Datenstruktur ist. Ausgehend von der Performance-POV gibt es sehr wenige Fälle, in denen LinkedList eine bessere Leistung erzielen könnte als die Cache-freundlichenArrayList.

Hier sind die Ergebnisse eines Benchmark-Tests, bei dem Elemente an zufälligen Orten eingefügt wurden. Wie Sie sehen, ist die Array-Liste viel effizienter, obwohl theoretisch für jede Einfügung in der Mitte der Liste die n späteren Elemente des Arrays "verschoben" werden müssen (niedrigere Werte sind besser) ):

enter image description here

Arbeiten an einer neueren Hardware-Generation (größere, effizientere Caches) - die Ergebnisse sind noch schlüssiger:

enter image description here

LinkedList benötigt viel mehr Zeit, um den gleichen Job auszuführen. QuelleQuellcode

Dafür gibt es zwei Hauptgründe:

  1. Hauptsächlich - dass die Knoten der LinkedList zufällig über den Speicher verteilt sind. RAM ("Random Access Memory") ist nicht wirklich zufällig und Speicherblöcke müssen abgerufen werden, um zwischengespeichert zu werden. Dieser Vorgang benötigt Zeit, und wenn solche Abrufe häufig vorkommen - die Speicherseiten in der Cache muss ständig ausgetauscht werden -> Cache-Fehler -> Cache ist nicht effizient. ArrayList - Elemente werden im fortlaufenden Speicher gespeichert - genau dafür optimiert die moderne CPU-Architektur.

  2. Sekundär LinkedList erforderlich, um Rück-/Vorwärtszeiger zu speichern, was das Dreifache des Speicherverbrauchs pro gespeichertem Wert im Vergleich zu ArrayList bedeutet ].

DynamicIntArray ist übrigens eine benutzerdefinierte ArrayList-Implementierung, die Int (primitiver Typ) und keine Objekte enthält - daher werden alle Daten wirklich nebeneinander gespeichert - und damit noch effizienter.

Ein wichtiges Element, an das man sich erinnern sollte, ist, dass die Kosten für das Abrufen eines Speicherblocks höher sind als die Kosten für den Zugriff auf eine einzelne Speicherzelle. Aus diesem Grund ist der Leser mit 1 MB sequentiellem Speicher bis zu 400-mal schneller als das Lesen dieser Datenmenge aus verschiedenen Speicherblöcken:

Latency Comparison Numbers (~2012)
----------------------------------
L1 cache reference                           0.5 ns
Branch mispredict                            5   ns
L2 cache reference                           7   ns                      14x L1 cache
Mutex lock/unlock                           25   ns
Main memory reference                      100   ns                      20x L2 cache, 200x L1 cache
Compress 1K bytes with Zippy             3,000   ns        3 us
Send 1K bytes over 1 Gbps network       10,000   ns       10 us
Read 4K randomly from SSD*             150,000   ns      150 us          ~1GB/sec SSD
Read 1 MB sequentially from memory     250,000   ns      250 us
Round trip within same datacenter      500,000   ns      500 us
Read 1 MB sequentially from SSD*     1,000,000   ns    1,000 us    1 ms  ~1GB/sec SSD, 4X memory
Disk seek                           10,000,000   ns   10,000 us   10 ms  20x datacenter roundtrip
Read 1 MB sequentially from disk    20,000,000   ns   20,000 us   20 ms  80x memory, 20X SSD
Send packet CA->Netherlands->CA    150,000,000   ns  150,000 us  150 ms

Quelle: Latenzzahlen, die jeder Programmierer kennen sollte

Um den Punkt noch deutlicher zu machen, überprüfen Sie bitte den Benchmark, in dem Elemente am Anfang der Liste hinzugefügt werden. Dies ist ein Anwendungsfall, bei dem theoretisch die LinkedList wirklich strahlen sollte und ArrayList schlechte oder sogar schlechtere Ergebnisse liefern sollte:

enter image description here

Hinweis: Dies ist ein Benchmark der C++ - Standardbibliothek, aber meine früheren Erfahrungen haben gezeigt, dass die Ergebnisse für C++ und Java) sehr ähnlich sind. Quellcode

Das Kopieren einer sequentiellen Speichermasse ist eine von den modernen CPUs optimierte Operation, bei der die Theorie geändert und die Effizienz von ArrayList/Vector nochmals deutlich gesteigert wird


Credits: Alle hier veröffentlichten Benchmarks wurden von Kjell Hedström erstellt. Weitere Daten finden Sie auf seinem Blog

17
Lior Bar-On

Vergleichen wir LinkedList und ArrayList w.r.t. unter parameter:

1. Implementierung

ArrayList ist die anpassbare Array-Implementierung der Listenschnittstelle, während 

LinkedList ist die Implementierung der Listenschnittstelle mit doppelt verknüpfter Liste.


2. Leistung

  • get (int index) oder Suchvorgang

    ArrayList get (int index) wird in konstanter Zeit ausgeführt, d. H. O(1), während 

    LinkedList get (int index) Operationslaufzeit ist O(n).

    Der Grund dafür, dass ArrayList schneller als LinkedList ist, besteht darin, dass ArrayList ein indexbasiertes System für seine Elemente verwendet, da es intern eine Array-Datenstruktur verwendet.

    LinkedList bietet keinen indexbasierten Zugriff für seine Elemente, da es entweder vom Anfang oder vom Ende (je nachdem, was näher ist) iteriert, um den Knoten am angegebenen Elementindex abzurufen.

  • einfügen () oder Hinzufügen (Objekt)

    Einfügungen in LinkedList sind im Allgemeinen vergleichbar mit ArrayList. In LinkedList ist das Hinzufügen oder Einfügen der Operation O(1). 

    Wenn in ArrayList das Array den vollständigen Wert (dh den ungünstigsten Fall) aufweist, entstehen zusätzliche Kosten für das Ändern der Größe des Arrays und das Kopieren von Elementen in das neue Array. Dies führt zur Laufzeit der Add-Operation in ArrayList O (n), andernfalls ist dies der Fall O (1).

  • (int) Operation entfernen

    Der Vorgang zum Entfernen in LinkedList entspricht im Allgemeinen dem von ArrayList, d. H. O (n).

    In LinkedList gibt es zwei überladene remove-Methoden. one ist remove () ohne einen Parameter, der den Kopf der Liste entfernt und in konstanter Zeit O (1) läuft. Die andere überladene remove-Methode in LinkedList ist remove (int) oder remove (Object), wodurch das als Parameter übergebene Object oder int entfernt wird. Diese Methode durchsucht die LinkedList, bis sie das Objekt gefunden hat, und hebt die Verknüpfung von der ursprünglichen Liste auf. Daher ist diese Methodenlaufzeit O (n). 

    Während der Methode remove (int) in ArrayList werden Elemente aus dem alten Array in ein neues aktualisiertes Array kopiert. Die Laufzeit ist daher O (n).


3. Umgekehrter Iterator

LinkedList kann mit descendingIterator () in umgekehrter Richtung durchlaufen werden 

es gibt keinen descendingIterator () in ArrayList. Daher müssen wir unseren eigenen Code schreiben, um die ArrayList in umgekehrter Richtung zu durchlaufen.


4. Anfangskapazität

Wenn der Konstruktor nicht überladen ist, erstellt ArrayList eine leere Liste mit der ursprünglichen Kapazität 10, während 

LinkedList erstellt nur die leere Liste ohne Anfangskapazität.


5. Speicheraufwand

Der Speicheraufwand in LinkedList ist mehr als bei ArrayList, da ein Knoten in LinkedList die Adressen des nächsten und vorherigen Knotens beibehalten muss. Während 

In ArrayList enthält jeder Index nur das eigentliche Objekt (Daten).


Quelle

Zusätzlich zu den anderen guten Argumenten oben sollten Sie Folgendes beachten: ArrayList implementiert RandomAccess-Schnittstelle, während LinkedListQueue implementiert.

Irgendwie adressieren sie etwas unterschiedliche Probleme, mit unterschiedlichen Effizienz- und Verhaltensunterschieden (siehe Methodenliste).

12
PhiLho
9
chharvey

Eine Array-Liste ist im Wesentlichen ein Array mit Methoden zum Hinzufügen von Elementen usw. (und Sie sollten stattdessen eine generische Liste verwenden). Es ist eine Sammlung von Elementen, auf die über einen Indexer zugegriffen werden kann (beispielsweise [0]). Dies impliziert einen Fortschritt von einem Element zum nächsten.

Eine verknüpfte Liste gibt einen Fortschritt von einem Element zum nächsten an (Element a -> Element b). Sie können den gleichen Effekt mit einer Array-Liste erzielen, aber eine verknüpfte Liste sagt absolut aus, welcher Artikel dem vorherigen folgen soll. 

8
kemiller2002

Es hängt davon ab, welche Operationen Sie auf der Liste ausführen werden.

ArrayList kann schneller auf einen indizierten Wert zugreifen. Beim Einfügen oder Löschen von Objekten ist es viel schlimmer.

Weitere Informationen finden Sie in den Artikeln, in denen der Unterschied zwischen Arrays und verknüpften Listen beschrieben wird.

7

Ich habe die Antworten gelesen, aber es gibt ein Szenario, in dem ich immer eine LinkedList über eine ArrayList verwende, die ich teilen möchte, um Meinungen zu hören:

Jedes Mal, wenn ich eine Methode hatte, die eine Liste von Daten aus einer Datenbank zurückgibt, verwende ich immer eine LinkedList.

Mein Grund war, dass es unmöglich ist, genau zu wissen, wie viele Ergebnisse ich bekomme, dass kein Speicherplatz verschwendet wird (wie in ArrayList mit dem Unterschied zwischen der Kapazität und der tatsächlichen Anzahl von Elementen) und es keine Zeit für den Versuch gibt Kapazität verdoppeln.

Soweit eine ArrayList, stimme ich zu, dass Sie zumindest den Konstruktor immer mit der ursprünglichen Kapazität verwenden sollten, um die Duplizierung der Arrays so gering wie möglich zu halten.

6
gaijinco

Eine wichtige Funktion einer verknüpften Liste (die ich nicht in einer anderen Antwort gelesen habe) ist die Verkettung zweier Listen. Bei einem Array ist dies O(n) (+ Overhead einiger Neuzuordnungen). Bei einer verknüpften Liste ist dies nur O(1) oder O(2) ;-).

Important: Für Java ist dessen LinkedList nicht wahr! Siehe Gibt es eine schnelle concat-Methode für verknüpfte Liste in Java?

6
Karussell

Normalerweise verwende ich eins nach dem anderen, basierend auf den zeitlichen Komplexitäten der Operationen, die ich für diese bestimmte Liste ausführen würde. 

|---------------------|---------------------|--------------------|------------|
|      Operation      |     ArrayList       |     LinkedList     |   Winner   |
|---------------------|---------------------|--------------------|------------|
|     get(index)      |       O(1)          |         O(n)       | ArrayList  |
|                     |                     |  n/4 steps in avg  |            |
|---------------------|---------------------|--------------------|------------|
|      add(E)         |       O(1)          |         O(1)       | LinkedList |
|                     |---------------------|--------------------|            |
|                     | O(n) in worst case  |                    |            |
|---------------------|---------------------|--------------------|------------|
|    add(index, E)    |       O(n)          |         O(n)       | LinkedList |
|                     |     n/2 steps       |      n/4 steps     |            |
|                     |---------------------|--------------------|            |
|                     |                     |  O(1) if index = 0 |            |
|---------------------|---------------------|--------------------|------------|
|  remove(index, E)   |       O(n)          |         O(n)       | LinkedList |
|                     |---------------------|--------------------|            |
|                     |     n/2 steps       |      n/4 steps     |            |
|---------------------|---------------------|--------------------|------------|
|  Iterator.remove()  |       O(n)          |         O(1)       | LinkedList |
|  ListIterator.add() |                     |                    |            |
|---------------------|---------------------|--------------------|------------|


|--------------------------------------|-----------------------------------|
|              ArrayList               |            LinkedList             |
|--------------------------------------|-----------------------------------|
|     Allows fast read access          |   Retrieving element takes O(n)   |
|--------------------------------------|-----------------------------------|
|   Adding an element require shifting | o(1) [but traversing takes time]  |
|       all the later elements         |                                   |
|--------------------------------------|-----------------------------------|
|   To add more elements than capacity |
|    new array need to be allocated    |
|--------------------------------------|
5

ArrayList und LinkedList implementieren beide List interface und ihre Methoden und Ergebnisse sind nahezu identisch. Es gibt jedoch nur wenige Unterschiede, die je nach Anforderung einen über den anderen verbessern.

ArrayList Vs LinkedList

1) Die Search:ArrayList-Suchoperation ist im Vergleich zur LinkedList-Suchoperation ziemlich schnell. get(int index) in ArrayList gibt die Leistung von O(1) an, während LinkedList Leistung O(n) ist.

Reason:ArrayList verwaltet ein indexbasiertes System für seine Elemente, da es die Array-Datenstruktur implizit verwendet, was die Suche nach einem Element in der Liste beschleunigt. Auf der anderen Seite implementiert LinkedList eine doppelt verknüpfte Liste, die den Durchlauf durch alle Elemente zum Durchsuchen eines Elements erfordert.

2) Deletion:LinkedList remove führt zu O(1), während ArrayList zu variabler Performance führt: O(n) im schlimmsten Fall (beim Entfernen des ersten Elements) und O(1) im besten Fall (beim Entfernen des letzten Elements).

Fazit: Das Löschen von LinkedList-Elementen ist im Vergleich zu .__ schneller. Anordnungsliste.

Grund: Jedes Element von LinkedList enthält zwei Zeiger (Adressen), die auf die beiden benachbarten Elemente in der Liste zeigen. Daher erfordert das Entfernen nur eine Änderung der Zeigerposition in den zwei Nachbarknoten (Elementen) des Knotens, der entfernt werden soll. In ArrayList müssen alle Elemente verschoben werden, um den durch das entfernte Element erstellten Platz auszufüllen.

3) Inserts Performance:LinkedList add-Methode verleiht O(1) Leistung, während ArrayListO(n) im schlimmsten Fall ergibt. Der Grund ist derselbe wie für das Entfernen.

4) Memory Overhead:ArrayList verwaltet Indizes und Elementdaten, während LinkedList Elementdaten und zwei Zeiger für benachbarte Knoten verwaltet 

daher ist der Speicherverbrauch in LinkedList vergleichsweise hoch.

Es gibt wenige Ähnlichkeiten zwischen diesen Klassen, die wie folgt lauten:

  • Sowohl ArrayList als auch LinkedList sind eine Implementierung der List-Schnittstelle.
  • Sie behalten beide die Einfügereihenfolge der Elemente bei, dh, bei der Anzeige von ArrayList- und LinkedList-Elementen würde die Ergebnismenge dieselbe Reihenfolge aufweisen, in der die Elemente in die Liste eingefügt wurden.
  • Beide Klassen sind nicht synchronisiert und können mithilfe der Collections.synchronizedList-Methode explizit synchronisiert werden.
  • Die von diesen Klassen zurückgegebenen iterator und listIterator sind fail-fast (wenn die Liste zu irgendeinem Zeitpunkt nach dem Erstellen des Iterators strukturell geändert wird, außer durch die iterator’s-eigenen Methoden zum Entfernen oder Hinzufügen, wird der Iterator throw eine ConcurrentModificationException).

Wann ist LinkedList und wann ArrayList zu verwenden?

  • Wie oben erläutert, ergeben die Einfüge- und Entnahmevorgänge eine gute Leistung (O(1)) in LinkedList im Vergleich zu ArrayList(O(n)).

    Wenn daher häufiges Hinzufügen und Löschen in der Anwendung erforderlich ist, ist LinkedList die beste Wahl.

  • Suchoperationen (get method) sind in Arraylist (O(1)) schnell, aber nicht in LinkedList (O(n))

    wenn weniger Vorgänge zum Hinzufügen und Entfernen erforderlich sind und mehr Suchvorgänge erforderlich sind, wäre ArrayList die beste Wahl.

5
Real73

Die Operation get (i) in ArrayList ist schneller als LinkedList, weil:
ArrayList: Resizable-Array-Implementierung der List-Schnittstelle
LinkedList: Doppelt verknüpfte Listenimplementierung der List- und Deque-Schnittstellen

Operationen, die in die Liste aufgenommen werden, durchlaufen die Liste vom Anfang oder vom Ende, je nachdem, welcher dem angegebenen Index näher ist. 

5
Amitābha

ArrayList und LinkedList haben ihre eigenen Vor- und Nachteile.

ArrayList verwendet zusammenhängende Speicheradressen im Vergleich zu LinkedList, die Zeiger auf den nächsten Knoten verwendet. Wenn Sie also nach einem Element in einer ArrayList suchen möchten, ist dies schneller als das Durchlaufen von N-Iterationen mit LinkedList.

Andererseits ist das Einfügen und Löschen in einer LinkedList viel einfacher, da Sie lediglich die Zeiger ändern müssen, während eine ArrayList die Verwendung einer Shift-Operation für das Einfügen oder Löschen impliziert.

Wenn in Ihrer App häufig Abrufvorgänge ausgeführt werden, verwenden Sie eine ArrayList. Bei häufigem Einfügen und Löschen verwenden Sie eine LinkedList. 

5
Nesan Mano

1) Basisdatenstruktur  

Der erste Unterschied zwischen ArrayList und LinkedList besteht darin, dass ArrayList von Array und von LinkedList durch LinkedList gesichert wird. Dies führt zu weiteren Leistungsunterschieden.

2) LinkedList implementiert Deque  

Ein weiterer Unterschied zwischen ArrayList und LinkedList besteht darin, dass LinkedList neben der List-Schnittstelle auch die Deque-Schnittstelle implementiert, die First-in-Out-Operationen für add () und poll () und mehrere andere Deque-Funktionen bereitstellt. 3) Hinzufügen von Elementen in ArrayList Das Hinzufügen von Elementen in ArrayList ist die Operation O(1), wenn keine erneute Größe des Arrays ausgelöst wird. In diesem Fall wird es zu O (log (n)). Das Anhängen eines Elements in LinkedList ist die Operation O(1), da keine Navigation erforderlich ist.

4) Entfernen eines Elements aus einer Position  

Um ein Element aus einem bestimmten Index zu entfernen, z. Durch Aufrufen von remove (Index) führt ArrayList eine Kopieroperation aus, die es nahe an O(n) heranführt, während LinkedList an diesen Punkt gelangen muss, was es auch zu O (n/2) macht, da es von jedem der beiden Ziele aus möglich ist Richtung basierend auf der Nähe.

5) Iteration über ArrayList oder LinkedList  

Die Iteration ist die Operation O(n) für LinkedList und ArrayList, wobei n die Nummer eines Elements ist.

6) Element von einer Position abrufen  

Die Operation get (index) ist in ArrayList O(1) und in LinkedList O(n/2), da bis zu diesem Eintrag durchlaufen werden muss. In der Big-O-Notation ist O(n/2) jedoch einfach O(n), weil wir dort Konstanten ignorieren.

7) Speicher  

LinkedList verwendet das Wrapper-Objekt Entry, eine statische verschachtelte Klasse zum Speichern von Daten und zwei Knoten neben und vor, während ArrayList nur Daten in Array speichert.

Die Speicheranforderung scheint also bei ArrayList geringer als bei LinkedList zu sein, mit Ausnahme des Falls, bei dem Array die Größenänderung vornimmt, wenn es Inhalt von einem Array in ein anderes kopiert.

Wenn das Array groß genug ist, kann an diesem Punkt viel Speicherplatz erforderlich sein und die Garbage Collection ausgelöst werden, was die Antwortzeit verlangsamen kann.

Aufgrund der oben genannten Unterschiede zwischen ArrayList und LinkedList scheint ArrayList in fast allen Fällen die bessere Wahl als LinkedList zu sein, es sei denn, Sie führen eine häufige add () - Operation aus als remove () oder get ().

Es ist einfacher, eine verknüpfte Liste als ArrayList zu ändern, insbesondere wenn Sie Elemente vom Anfang oder Ende hinzufügen oder entfernen, da die verknüpfte Liste intern Verweise auf diese Positionen enthält und auf sie innerhalb der Zeit O(1) zugegriffen werden kann.

Mit anderen Worten, Sie müssen die verknüpfte Liste nicht durchlaufen, um die Position zu erreichen, an der Sie Elemente hinzufügen möchten. In diesem Fall wird der Zusatz O(n). Beispielsweise können Sie ein Element in der Mitte einer verknüpften Liste einfügen oder löschen.

Meiner Meinung nach verwenden Sie ArrayList über LinkedList für die meisten praktischen Zwecke in Java.

3
Anjali Suman

Sowohl remove () als auch insert () haben für ArrayLists und LinkedLists eine Laufzeiteffizienz von O(n). Der Grund für die lineare Bearbeitungszeit hat jedoch zwei sehr unterschiedliche Gründe:

In einer ArrayList gelangen Sie zu dem Element in O (1). Wenn Sie jedoch etwas entfernen oder einfügen, wird es zu O(n), da alle folgenden Elemente geändert werden müssen.

In einer LinkedList benötigen Sie O(n), um tatsächlich zum gewünschten Element zu gelangen, da wir ganz am Anfang beginnen müssen, bis wir den gewünschten Index erreichen. Das Entfernen oder Einfügen ist tatsächlich konstant, da wir nur 1 Referenz für remove () und 2 Referenzen für insert () ändern müssen.

Welcher der beiden zum Einfügen und Entfernen schneller ist, hängt davon ab, wo er auftritt. Wenn wir näher am Anfang sind, wird die LinkedList schneller sein, weil wir relativ wenige Elemente durchlaufen müssen. Wenn wir uns dem Ende nähern, wird eine ArrayList schneller sein, da wir in konstanter Zeit dorthin gelangen und nur die wenigen verbleibenden Elemente ändern müssen, die ihr folgen. Wenn genau in der Mitte gearbeitet wird, ist die LinkedList schneller, da das Durchlaufen von n Elementen schneller ist als das Verschieben von n Werten.

Bonus: Obwohl es keine Möglichkeit gibt, diese beiden Methoden O(1) für eine ArrayList zu erstellen, gibt es tatsächlich eine Möglichkeit, dies in LinkedLists zu tun. Angenommen, wir möchten die gesamte Liste durchgehen und Elemente entfernen und auf unserem Weg einfügen. Normalerweise fangen Sie für jedes Element mit der LinkedList am Anfang an, wir könnten auch das aktuelle Element, an dem wir arbeiten, mit einem Iterator "speichern". Mit Hilfe des Iterators erhalten wir beim Arbeiten in einer LinkedList eine Effizienz von O(1) für remove () und insert (). Ich bin mir der Tatsache bewusst, dass eine LinkedList immer besser ist als eine ArrayList.

1
pietz

ArrayList erweitert AbstractList und implementiert die Listenschnittstelle. ArrayList ist ein dynamisches Array.
Es kann gesagt werden, dass es im Grunde geschaffen wurde, um die Nachteile von Arrays zu überwinden

Die LinkedList-Klasse erweitert AbstractSequentialList und implementiert die Schnittstelle List, Deque und Queue .
Performance
arraylist.get() ist O(1), während linkedlist.get() O(n) ist. 
arraylist.add() ist O(1) und linkedlist.add() ist 0 (1)
arraylist.contains() ist O(n) undlinkedlist.contains() ist O(n) 
arraylist.next() ist O(1) und linkedlist.next() ist O (1)
arraylist.remove() ist O(n), wohingegen linkedlist.remove() O (1) ist.
In Arrayliste
iterator.remove() ist O (n)
während in verknüpfter Liste 
iterator.remove()is O(1) 

0
Randhawa

Einer der Tests, die ich hier gesehen habe, führt den Test nur einmal durch. Ich habe jedoch festgestellt, dass Sie diese Tests viele Male ausführen müssen, und ihre Zeiten werden möglicherweise zusammenlaufen. Grundsätzlich muss die JVM aufwärmen. Für meinen speziellen Anwendungsfall musste ich Elemente zu einem Leisten hinzufügen/entfernen, der auf etwa 500 Elemente anwächst. In meinen Tests kam LinkedList schneller heraus, wobei verknüpfte LinkedList etwa 50.000 NS und ArrayList etwa 90.000 NS waren. Siehe den Code unten.

public static void main(String[] args) {
    List<Long> times = new ArrayList<>();
    for (int i = 0; i < 100; i++) {
        times.add(doIt());
    }
    System.out.println("avg = " + (times.stream().mapToLong(x -> x).average()));
}

static long doIt() {
    long start = System.nanoTime();
    List<Object> list = new LinkedList<>();
    //uncomment line below to test with ArrayList
    //list = new ArrayList<>();
    for (int i = 0; i < 500; i++) {
        list.add(i);
    }

    Iterator it = list.iterator();
    while (it.hasNext()) {
        it.next();
        it.remove();
    }
    long end = System.nanoTime();
    long diff = end - start;
    //uncomment to see the JVM warmup and get faster for the first few iterations
    //System.out.println(diff)
    return diff;
}
0
Jose Martinez