2013-04-17 13 views
6

Wie im Titel. Ich weiß, dass es wahrscheinlich zwei Unterlisten vor und nach gelöschten Elementen zusammenführt, aber wie verhält sich diese Methode beim Entfernen von LAST-Elementen? Mit anderen Worten: Macht es irgendwie eine Kopie aller Elemente, die sich vor dem Entfernen des Index befinden? Ich bin nur neugierig auf die Leistung der Verwendung von RemoveRange auf einer riesigen Liste (sagen wir 5000 Elemente), nur um z. B. zu entfernen. nur die letzten 2 von ihnen.Wie funktioniert die RemoveRange() - Methode in einer Liste <>?

Wenn es dann eine Kopie macht, gibt es eine Möglichkeit, eine interne Variable zu ändern, die die Größe der Liste einstellt (und Rest der zugeordneten Elemente als Müll behandeln)?

Ich habe nur eine Information gefunden, dass es ein O (n) Komplexitätsalgorithmus ist, aber ich bin mir nicht sicher, ob das "n" in diesem Fall eine Listengröße oder eine Anzahl zu löschender Elemente ist.

Wir freuen uns über jeden Hinweis.

+0

http://msdn.microsoft.com/en-gb/library/y33yd2b5.aspx "Diese Methode ist eine O (n) -Operation, wobei n Count ist." "Die Elemente werden entfernt und alle Elemente, die ihnen in der Liste folgen, werden um die Anzahl ihrer Indizes reduziert." http://geekswithblogs.net/BlackRabbitCoder/archive/2012/02/23/c.net-little-wondersndashthe-listlttgt-range-methods.aspx "Beachten Sie, dass dies dazu führt, dass der Rest der Liste nach unten verschoben werden muss füllen Sie die Lücke, die nicht trivial sein kann.Es wird jedoch keine Neuzuweisung der Liste erforderlich sein, da die Größe möglicherweise schrumpft, nicht wächst. " –

+1

Komm, du denkst, dass count die zu entfernende Zahl ist. Das Entfernen von 2 aus einer Liste von zehn dauert genauso lange Entfernen von 2 von einer Million Wenn Sie auf die Anzahl in der Dokumentation klicken, wird die Anzahl der Listen verknüpft. – Paparazzi

+1

@Blam Das ist nicht wahr, es sei denn, Sie entfernen am Ende der Liste. Wenn Sie am Anfang der Liste entfernen dann ist es der Unterschied zwischen dem Verschieben von 8 Elementen im Speicher um zwei Elemente gegenüber dem Verschieben von 1.999.998 Elementen im Speicher um zwei Elemente, die nicht gleich sein werden – Servy

Antwort

10

Es wird jedes Element nach dem Ende des Bereichs von Elementen, die entfernt werden sollen, genommen und in der Liste nach der Anzahl der Elemente verschoben, die entfernt wurden. Im Hinblick auf die Auswirkungen auf die Leistung wird es nach dem Ende des Bereichs der verschobenen Artikel eine Kopie für jeden Artikel geben. Dies bedeutet, dass es am besten funktioniert, wenn es vom Ende entfernt wird (es wird O (1) sein), und führt am schlechtesten aus, wenn es von Anfang an entfernt wird (O (n)).

Als Beispiel betrachten wir die folgende Liste:

index - value 

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

Wenn wir RemoveRange(2, 2) rufen dann sind wir zwei Punkte entfernt an der Position index 2, so dass wir entfernen C und D.

Diese bedeutet, dass E in den Index 2 kopiert werden muss, dann muss F in den Index 3 kopiert werden, und G muss in den Index 4 kopiert werden. Nach dem letzten entfernten Objekt gibt es einen Kopiervorgang für jedes Element.

Beachten Sie, dass aufgrund der Tatsache, dass Sie den gesamten Speicherblock um "zwei" nach oben verschieben können, dies in der Praxis effizienter ist, dass jedes Element einzeln kopiert wird. Es ist viel einfacher für einen Computerspeicher, einen ganzen Speicherblock um eine bestimmte Anzahl von Bytes zu verschieben, als viele kleine Speicherbereiche an verschiedene willkürliche Speicherorte zu verschieben. Es wird jedoch die gleiche asymptotische Komplexität haben.

+0

Genau das wollte ich wissen, danke. – Tarec

13

List<T> ist nur ein Wrapper um ein Array, im folgenden Code _items genannt. Das Array enthält möglicherweise mehr Slots als Elemente in der Liste. Daher wird _size verwendet, um zu verfolgen, wie viele tatsächlich gültig sind. Wenn Sie das tun ein RemoveRange(index, count) ...

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

... es kopiert die Elemente aus früherem Bereich in den leeren Raum, und löschen die alten Elemente.

Wenn Sie einen Bereich nahe am Anfang einer großen Liste entfernen, dann sind die Kosten proportional zur Größe der Liste, weil so viele Dinge nach unten verschoben werden müssen.

Wenn Sie einen großen Bereich nahe am Ende einer großen Liste entfernen, ist das Kopieren zwar billig, aber das Löschen ist teuer, so dass die Kosten proportional zur Größe des entfernten Bereichs sind.

+1

Könnten Sie bitte etwas genauer erklären, warum Clearing im zweiten Fall teuer ist? Wie ich verstanden habe, müssen wir nur betroffene Elemente des Arrays löschen, deren Anzahl nicht so groß ist wie '_size' oder' _items.Length' im Falle einer großen Liste. Zum Beispiel, wenn Sie in der großen Liste nahe dem Anfang oder nahe dem Ende kleine Reichweite entfernen. –

+0

Bedeutet das, ich sollte eine 'LinkedList ' verwenden. Wenn ich weiß, dass die Liste groß sein wird und ich später Elemente entfernen möchte? – Jodrell

+2

@Jodrell Wahrscheinlich nicht. Wenn eine verknüpfte Liste verwendet wird, führt der Verlust der Speicherlokalität zu einer sehr schlechten Leistung, selbst für einfache Aufgaben wie das Iterieren der verknüpften Liste. Während die Big-O-Werte vieler seiner Operationen niedrig sind, ist es für verknüpfte Listen in den meisten praktischen Fällen ungewöhnlich, ein Nettogewinn zu sein. – Servy

Verwandte Themen