Podsumowanie ArrayList z ArrayDequejest lepsze w znacznie większej liczbie przypadków użycia niż LinkedList. Jeśli nie jesteś pewien - zacznij od ArrayList.
LinkedListi ArrayListsą dwiema różnymi implementacjami interfejsu List. LinkedListimplementuje go z podwójnie połączoną listą. ArrayListimplementuje 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 = 0lub 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 = 0lub 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 = 0lub 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 ArrayListjest 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 LinkedListpowstają, 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 LinkedListsposób podążający za linkami w O (n) ( n / 2 krokach) w najgorszym przypadku, podczas gdy w ArrayListpożądanej pozycji można obliczyć matematycznie i uzyskać dostęp w O (1) .
Kolejna korzyść z używania LinkedListpojawia 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 ArrayDequemoż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 LinkedListma większy narzut, ponieważ przechowywane są również wskaźniki do następnego i poprzednich elementów. ArrayListsnie 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ść ArrayListjest 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 ArrayListwiększą pojemność początkową.