Czytając dokumentację Java dla listy ADT mówi:
Interfejs List udostępnia cztery metody pozycyjnego (indeksowanego) dostępu do elementów listy. Listy (podobnie jak tablice Java) są liczone od zera. Zauważ, że te operacje mogą być wykonywane w czasie proporcjonalnym do wartości indeksu dla niektórych implementacji (na przykład klasy LinkedList). W związku z tym iteracja po elementach listy jest zwykle lepsza niż indeksowanie za jej pośrednictwem, jeśli obiekt wywołujący nie zna implementacji.
Co to dokładnie oznacza? Nie rozumiem wyciągniętego wniosku.
Odpowiedzi:
Na połączonej liście każdy element ma wskaźnik do następnego elementu:
Aby uzyskać dostęp
item3
, możesz wyraźnie zobaczyć, że musisz przejść od głowy przez każdy węzeł, aż dotrzesz do elementu 3, ponieważ nie możesz skoczyć bezpośrednio.Tak więc, gdybym chciał wydrukować wartość każdego elementu, jeśli napiszę to:
co się dzieje to:
Jest to okropnie nieefektywne, ponieważ za każdym razem, gdy indeksujesz, jest ono uruchamiane od początku listy i przechodzi przez wszystkie pozycje. Oznacza to, że Twoja złożoność polega na skutecznym
O(N^2)
przejściu przez listę!Jeśli zamiast tego zrobiłem to:
to co się dzieje to:
wszystko w jednym przejściu, czyli
O(N)
.Teraz idzie na inne zastosowania
List
, które jestArrayList
, że jeden jest wspierany przez proste tablicy. W takim przypadku oba powyższe przejścia są równoważne, ponieważ tablica jest ciągła, więc umożliwia losowe skoki do dowolnych pozycji.źródło
REVERSE_THRESHOLD
jest ustawiony na 18 cali,java.util.Collections
dziwnie jest widzieć tak pozytywną odpowiedź bez uwagi.List l = unknownList(); if (l instanceof RandomAccess) /* do indexed loop */ else /* use iterator/foreach */
Odpowiedź jest implikowana tutaj:
Lista połączona nie ma własnego indeksu; wywołanie
.get(x)
będzie wymagało implementacji listy w celu znalezienia pierwszego wpisu i wywołania.next()
x-1 razy (dla dostępu O (n) lub czasu liniowego), gdzie lista oparta na tablicy może po prostu indeksowaćbackingarray[x]
w O (1) lub w czasie stałym.Jeśli spojrzysz na JavaDoc
LinkedList
, zobaczysz komentarzpodczas gdy JavaDoc dla
ArrayList
ma odpowiedni plikPokrewne pytanie zatytułowany „Big-O Podsumowanie Java Collections Framework” ma wskazując odpowiedź na to zasób, „Java Collections JDK6” , który można znaleźć pomocne.
źródło
Chociaż przyjęta odpowiedź jest z pewnością poprawna, czy mógłbym wskazać drobną wadę. Cytując Tudora:
To nie jest do końca prawdą. Prawda jest taka, że
źródło: Designing for Performance, dokument Google na temat Androida
Zauważ, że odręczna pętla odnosi się do indeksowanej iteracji. Podejrzewam, że to z powodu iteratora, który jest używany z ulepszonymi pętlami for. Daje niewielką wydajność w postaci kary w strukturze, która jest obsługiwana przez ciągłą tablicę. Podejrzewam również, że może to dotyczyć klasy Vector.
Moja zasada brzmi: używaj rozszerzonej pętli for, gdy tylko jest to możliwe, a jeśli naprawdę zależy Ci na wydajności, używaj indeksowanej iteracji tylko dla ArrayLists lub Vector. W większości przypadków możesz to nawet zignorować - kompilator może optymalizować to w tle.
Chcę tylko zaznaczyć, że w kontekście programowania w systemie Android oba przejścia ArrayLists niekoniecznie są równoważne . Po prostu do przemyślenia.
źródło
Iterowanie po liście z przesunięciem dla wyszukiwania, takim jak
i
, jest analogiczne do algorytmu malarza Shlemiela .Źródło .
Ta krótka historia może ułatwić zrozumienie tego, co dzieje się wewnętrznie i dlaczego jest tak nieefektywna.
źródło
Aby znaleźć i-ty element
LinkedList
implementacji, przechodzi przez wszystkie elementy aż do i-tego.Więc
źródło