Podsumowanie ArrayList
z ArrayDeque
jest lepsze w znacznie większej liczbie przypadków użycia niż LinkedList
. Jeśli nie jesteś pewien - zacznij od ArrayList
.
LinkedList
i ArrayList
są dwiema różnymi implementacjami interfejsu List. LinkedList
implementuje go z podwójnie połączoną listą. ArrayList
implementuje go za pomocą dynamicznie zmieniającej się tablicy.
Podobnie jak w przypadku standardowych połączonych operacji na liście i tablicach, różne metody będą miały różne środowiska uruchomieniowe algorytmu.
Dla LinkedList<E>
get(int index)
to O (n) ( średnio n / 4 kroki), ale O (1), gdy index = 0
lub index = list.size() - 1
(w tym przypadku możesz także użyć getFirst()
i getLast()
). Jedną z głównych zalet LinkedList<E>
add(int index, E element)
to O (n) ( średnio z n / 4 krokami), ale O (1), gdy index = 0
lub index = list.size() - 1
(w tym przypadku można również użyć addFirst()
i addLast()
/ add()
). Jedną z głównych zalet LinkedList<E>
remove(int index)
to O (n) ( średnio n / 4 kroki), ale O (1), gdy index = 0
lub index = list.size() - 1
(w tym przypadku możesz także użyć removeFirst()
i removeLast()
). Jedną z głównych zalet LinkedList<E>
Iterator.remove()
oznacza O (1) . Jedną z głównych zalet LinkedList<E>
ListIterator.add(E element)
oznacza O (1) . Jedną z głównych zalet LinkedList<E>
Uwaga: wiele operacji wymaga n / 4 średnio kroków, stałej liczby kroków w najlepszym przypadku (np. Indeks = 0) i n / 2 kroków w najgorszym przypadku (środek listy)
Dla ArrayList<E>
get(int index)
to O (1) . Główną zaletą ArrayList<E>
add(E element)
to O (1) amortyzowane przez , ale w najgorszym przypadku O (n), ponieważ rozmiar tablicy musi zostać zmieniony i skopiowany
add(int index, E element)
to O (n) ( średnio n / 2 kroki)
remove(int index)
to O (n) ( średnio n / 2 kroki)
Iterator.remove()
to O (n) ( średnio n / 2 kroki)
ListIterator.add(E element)
oznacza O (n) (zśrednio n / 2 kroki)
Uwaga: wiele operacji wymaga średnio n / 2 kroków, stałych liczby kroków w najlepszym przypadku (koniec listy), n kroków w najgorszym przypadku (początek listy)
LinkedList<E>
pozwala na wstawianie lub usuwanie w stałym czasie za pomocą iteratorów , ale tylko sekwencyjny dostęp do elementów. Innymi słowy, możesz przejść listę do przodu lub do tyłu, ale znalezienie pozycji na liście zajmuje czas proporcjonalny do wielkości listy. Javadoc mówi: „operacje indeksujące listę będą przechodzić przez listę od początku lub końca, w zależności od tego, co jest bliższe” , więc te metody to średnio O (n) ( n / 4 kroki), chociaż O (1) dla index = 0
.
ArrayList<E>
, z drugiej strony, umożliwia szybki losowy dostęp do odczytu, dzięki czemu można pobrać dowolny element w stałym czasie. Ale dodawanie lub usuwanie z dowolnego miejsca poza końcem wymaga przesunięcia wszystkich ostatnich elementów, aby zrobić otwór lub wypełnić lukę. Ponadto, jeśli dodasz więcej elementów niż pojemność tablicy bazowej, przydzielana jest nowa tablica (1,5 razy większa), a stara tablica jest kopiowana do nowej, więc dodawanie doArrayList
jest O (n) w najgorszym przypadek, ale średnio stały.
Dlatego w zależności od operacji, które zamierzasz wykonać, powinieneś odpowiednio wybrać implementacje. Iterowanie po każdym rodzaju listy jest praktycznie równie tanie. (Iteracja ArrayList
jest technicznie szybsza, ale jeśli nie robisz czegoś naprawdę wrażliwego na wydajność, nie powinieneś się tym przejmować - oba są stałe.)
Główne zalety używania LinkedList
powstają, gdy ponownie wykorzystujesz istniejące iteratory do wstawiania i usuwania elementów. Operacje te można następnie wykonać w O (1) , zmieniając listę tylko lokalnie. Na liście tablic pozostałą część tablicy należy przenieść (tzn. Skopiować). Z drugiej strony, szukanie w LinkedList
sposób podążający za linkami w O (n) ( n / 2 krokach) w najgorszym przypadku, podczas gdy w ArrayList
pożądanej pozycji można obliczyć matematycznie i uzyskać dostęp w O (1) .
Kolejna korzyść z używania LinkedList
pojawia się, gdy dodajesz lub usuwasz z nagłówka listy, ponieważ te operacje to O (1) , podczas gdy są one O (n) dla ArrayList
. Pamiętaj, że ArrayDeque
może to być dobra alternatywa dlaLinkedList
dla dodawania i usuwania z głowy, ale nie jest to List
.
Ponadto, jeśli masz duże listy, pamiętaj, że użycie pamięci jest również inne. Każdy element a LinkedList
ma większy narzut, ponieważ przechowywane są również wskaźniki do następnego i poprzednich elementów. ArrayLists
nie mam tego narzutu. Jednak,ArrayLists
zajmij tyle pamięci, ile jest przydzielone dla pojemności, niezależnie od tego, czy elementy zostały rzeczywiście dodane.
Domyślna początkowa pojemność ArrayList
jest dość mała (10 z Java 1.4 - 1.8). Ponieważ jednak podstawową implementacją jest tablica, należy zmienić jej rozmiar, jeśli dodasz wiele elementów. Aby uniknąć wysokich kosztów zmiany rozmiaru, gdy wiesz, że zamierzasz dodać wiele elementów, stwórz ArrayList
większą pojemność początkową.