Właściwie napisałem post na blogu na ten temat 2 miesiące temu. Artykuł jest przeznaczony dla C #, List<T>
ale Java ArrayList
ma bardzo podobną implementację. Ponieważ ArrayList
jest implementowany przy użyciu tablicy dynamicznej, zwiększa się na żądanie. Dlatego konstruktor pojemności ma na celu optymalizację.
Gdy wystąpi jedna z tych operacji zmiany rozmiaru, ArrayList kopiuje zawartość tablicy do nowej tablicy, która ma dwukrotnie większą pojemność niż stara. Ta operacja działa w czasie O (n) .
Przykład
Oto przykład, jak ArrayList
zwiększyłby się rozmiar:
10
16
25
38
58
... 17 resizes ...
198578
297868
446803
670205
1005308
Tak więc lista zaczyna się od pojemności 10
, po dodaniu 11. pozycji jest ona zwiększana o 50% + 1
do 16
. Na 17. pozycji wartość ArrayList
jest ponownie zwiększana do 25
i tak dalej. Rozważmy teraz przykład, w którym tworzymy listę, na której żądana pojemność jest już znana jako 1000000
. Utworzenie konstruktora ArrayList
bez rozmiaru wywołuje ArrayList.add
1000000
czasy, które normalnie przyjmują O (1) lub O (n) przy zmianie rozmiaru.
1000000 + 16 + 25 + ... + 670205 + 1005308 = 4015851 operacji
Porównaj to przy użyciu konstruktora, a następnie wywołanie, ArrayList.add
które ma gwarantowane działanie w O (1) .
1000000 + 1000000 = 2000000 operacji
Java vs C #
Java działa jak powyżej, zaczynając od 10
i zwiększając każdą zmianę rozmiaru o 50% + 1
. C # zaczyna się od 4
i rośnie znacznie agresywniej, podwajając się przy każdej zmianie rozmiaru. 1000000
Dodaje przykład od góry do C # używa 3097084
operacji.
Bibliografia