2013-04-17 3 views
6

Podobnie jak w tytule. Wiem, że prawdopodobnie łączy 2 podlisty przed i po usuniętych elementach, ale jak zachowuje się ta metoda podczas usuwania elementów OSTATNIEGO? Innymi słowy: czy w jakiś sposób tworzy kopię wszystkich elementów znajdujących się przed indeksem usuwania? Jestem po prostu ciekawa, jak wykorzystać funkcję RemoveRange na gigantycznej liście (powiedzmy 5000 elementów), aby usunąć f.e. tylko ostatnie 2 z nich.Jak działa metoda RemoveRange() na liście <>?

Jeśli tworzy kopię, czy istnieje sposób na zmianę wewnętrznej zmiennej, która ustawia rozmiar listy (i traktuje resztę przydzielonych elementów jako śmieci)?

Udało mi się tylko znaleźć informację, że jest to algorytm złożoności O (n), ale nie jestem pewien, czy "n" w tym przypadku jest wielkością Listy, czy też liczbą elementów do usunięcia.

Będzie zadowolony z wszelkich wskazówek.

+0

http://msdn.microsoft.com/en-gb/library/y33yd2b5.aspx "Ta metoda jest operacją O (n), gdzie n to liczba." "Elementy są usuwane, a wszystkie elementy występujące po nich na liście mają zmniejszone indeksy według liczby." http://geekswithblogs.net/BlackRabbitCoder/archive/2012/02/23/c.net-little-wondersndashthe-listlttgt-range-methods.aspx "należy pamiętać, że powoduje to konieczność przesunięcia reszty listy do wypełnić lukę, która może być nietrywialna.Jednak nie będzie to wymagać ponownego przydzielenia listy, ponieważ rozmiar potencjalnie się zmniejsza, a nie rośnie. " –

+1

Przyjdź, że uważasz, że liczba to liczba do usunięcia. Usunięcie 2 z listy dziesięciu zajmie tyle samo czasu, co usuwanie 2 z miliona Jeśli klikniesz liczbę w dokumentacji, która łączy Licznik list – Paparazzi

+1

@Blam To nie jest prawda, chyba że usuwasz z końca listy. Jeśli usuwasz z początku listy to jest różnica pomiędzy przesunięciem 8 przedmiotów w pamięci o dwa przedmioty, a przesunięciem 1 999 999 przedmiotów w pamięci o dwa przedmioty. Te dwa elementy nie będą równe: – Servy

Odpowiedz

10

To, co zrobi, to usunięcie każdego z przedmiotów po końcu zakresu pozycji i przesunięcie go na liście o liczbę usuniętych elementów. Pod względem implikacji wydajnościowych będzie jedna kopia dla każdej pozycji po końcu zakresu przeniesionych pozycji. Oznacza to, że będzie on działał najlepiej podczas usuwania z końca (będzie to O (1)) i będzie najgorszy podczas usuwania od początku (O (n)).

Jako przykład rozważmy następującą listę:

index - value 

0 - A 
1 - B 
2 - C 
3 - D 
4 - E 
5 - F 
6 - G

Jeśli nazywamy RemoveRange(2, 2) Następnie usuwamy dwa elementy zaczynając od indeksu 2, więc mamy do usuwania C i D.

ten oznacza, że ​​E musi zostać skopiowane do indeksu 2, następnie F musi zostać skopiowane do indeksu 3, a G musi zostać skopiowane do indeksu 4. Dla każdego elementu po usunięciu ostatniego elementu jest wykonywana jedna operacja kopiowania.

Należy pamiętać, że ze względu na to, że można przenieść cały blok pamięci "w górę" o dwa, w praktyce oznacza to, że kopiowanie każdego elementu odbywa się indywidualnie. O wiele łatwiej jest pamięci komputera przenieść cały blok pamięci o określoną stałą liczbę bajtów, niż przenieść wiele małych sekcji pamięci do różnych dowolnych lokalizacji. Będzie mieć jednakową złożoność asymptotyczną.

+0

Dokładnie to chciałem wiedzieć, dziękuję. – Tarec

13

List<T> to tylko opakowanie wokół tablicy o nazwie _items w poniższym kodzie. Tablica może mieć więcej slotów niż pozycji na liście, więc _size służy do śledzenia, ile z nich jest rzeczywiście poprawnych. Po wykonaniu RemoveRange(index, count) ...

_size -= count; 
if (index < _size) 
    Array.Copy(_items, index + count, _items, index, _size - index); 
Array.Clear(_items, _size, count); 

... kopiuje elementy z przeszłości zakresie do teraz pustej przestrzeni, a wyczyszczenie starych przedmiotów.

Jeśli usuwasz zakres bliski początku dużej listy, koszt jest proporcjonalny do rozmiaru listy, ponieważ tak wiele rzeczy musi zostać przesuniętych w dół.

Jeśli usuwasz duży zakres blisko końca dużej listy, kopiowanie jest tanie, ale rozliczenie jest kosztowne, więc koszt będzie proporcjonalny do rozmiaru usuniętego zakresu.

+1

Czy mógłbyś, proszę, pójść trochę głębiej, dlaczego rozliczanie jest kosztowne w drugim przypadku? Jak zrozumiałem, musimy wyczyścić tylko uszkodzone elementy tablicy, których wielkość nie jest tak duża, jak "_ rozmiar" lub "_items.Length" w przypadku dużej listy. Na przykład, jeśli usuwasz mały zakres na dużej liście w pobliżu początku lub końca. –

+0

Czy to oznacza, że ​​powinienem użyć 'LinkedList ' Jeśli wiem, że lista będzie duża i będę chciał usunąć przedmioty później? – Jodrell

+2

@Jodrell Prawdopodobnie nie. Podczas korzystania z listy połączonej utrata miejsca w pamięci powoduje bardzo niską wydajność, nawet w przypadku prostych zadań, takich jak iterowanie połączonej listy. Podczas gdy wartości Big O wielu z jego operacji są niskie, nie jest to często spotykane w przypadku list z linkami, aby w większości praktycznych przypadków uzyskać wygraną netto. – Servy