Lesen Sie die Java-Dokumentation für die ADT-Liste :
Die List-Schnittstelle bietet vier Methoden für den positionellen (indizierten) Zugriff auf Listenelemente. Listen (wie Java-Arrays) basieren auf Null. Beachten Sie, dass diese Operationen bei einigen Implementierungen (z. B. der LinkedList-Klasse) zeitlich proportional zum Indexwert ausgeführt werden können. Daher ist das Iterieren über die Elemente in einer Liste in der Regel der Indizierung vorzuziehen, wenn der Aufrufer die Implementierung nicht kennt.
Was genau bedeutet das? Ich verstehe die Schlussfolgerung nicht.
Antworten:
In einer verknüpften Liste hat jedes Element einen Zeiger auf das nächste Element:
Um darauf zugreifen zu können
item3
, können Sie deutlich sehen, dass Sie vom Kopf durch jeden Knoten gehen müssen, bis Sie Punkt 3 erreichen, da Sie nicht direkt springen können.Wenn ich also den Wert jedes Elements drucken möchte, wenn ich Folgendes schreibe:
Was passiert ist folgendes:
Dies ist schrecklich ineffizient, da es jedes Mal, wenn Sie indizieren, am Anfang der Liste neu startet und jedes Element durchläuft. Dies bedeutet, dass Ihre Komplexität effektiv
O(N^2)
nur darin besteht, die Liste zu durchlaufen!Wenn ich stattdessen folgendes tun würde:
dann passiert folgendes:
alles in einer einzigen Durchquerung, das heißt
O(N)
.Jetzt gehen, auf die andere Implementierung von
List
denenArrayList
, die man durch eine einfache Anordnung unterstützt wird. In diesem Fall sind beide oben genannten Durchläufe äquivalent, da ein Array zusammenhängend ist und zufällige Sprünge zu beliebigen Positionen ermöglicht.quelle
REVERSE_THRESHOLD
ist 18java.util.Collections
Zoll eingestellt , es ist seltsam, eine so optimierte Antwort ohne die Bemerkung zu sehen.List l = unknownList(); if (l instanceof RandomAccess) /* do indexed loop */ else /* use iterator/foreach */
Die Antwort ist hier impliziert:
Eine verknüpfte Liste hat keinen inhärenten Index. Für das Aufrufen
.get(x)
muss die Listenimplementierung den ersten Eintrag finden und.next()
x-1-mal aufrufen (für einen O (n) - oder linearen Zeitzugriff), wobei eine Array-gesicherte Liste nurbackingarray[x]
in O (1) oder konstanter Zeit indizieren kann .Wenn Sie sich JavaDoc ansehen
LinkedList
, wird der Kommentar angezeigtwährend JavaDoc für
ArrayList
das entsprechende hatEine verwandte Frage mit dem Titel "Big-O-Zusammenfassung für Java Collections Framework" enthält eine Antwort auf diese Ressource "Java Collections JDK6", die Sie möglicherweise hilfreich finden.
quelle
Obwohl die akzeptierte Antwort mit Sicherheit richtig ist, möchte ich auf einen kleinen Fehler hinweisen. Tudor zitieren:
Dies ist nicht ganz richtig. Die Wahrheit ist das
Quelle: Designing for Performance, Googles Android-Dokument
Beachten Sie, dass sich die handschriftliche Schleife auf die indizierte Iteration bezieht. Ich vermute, es liegt am Iterator, der mit Enhanced for Loops verwendet wird. In einer Struktur, die von einem zusammenhängenden Array unterstützt wird, wird eine geringfügige Strafe erzielt. Ich vermute auch, dass dies für die Vector-Klasse zutrifft.
Meine Regel lautet: Verwenden Sie nach Möglichkeit die erweiterte for-Schleife. Wenn Sie sich wirklich für die Leistung interessieren, verwenden Sie die indizierte Iteration nur für ArrayLists oder Vektoren. In den meisten Fällen können Sie dies sogar ignorieren - der Compiler optimiert dies möglicherweise im Hintergrund.
Ich möchte nur darauf hinweisen, dass im Kontext der Entwicklung in Android beide Durchläufe von ArrayLists nicht unbedingt gleichwertig sind . Nur Denkanstöße.
quelle
Das Durchlaufen einer Liste mit einem Versatz für die Suche, z. B.
i
, ist analog zu Shlemiel, dem Algorithmus des Malers .Quelle .
Diese kleine Geschichte kann es einfacher machen zu verstehen, was intern vor sich geht und warum sie so ineffizient ist.
quelle
Um das i-te Element von a zu finden
LinkedList
, durchläuft die Implementierung alle Elemente bis zum i-ten.So
quelle