2013-04-17 4 views
6

Как и в заголовке. Я знаю, что это, вероятно, объединяет 2 подсписок до и после удаленных элементов, но как этот метод ведет себя при удалении элементов LAST? Другими словами: делает ли он каким-то образом копию всех элементов, расположенных перед удалением индекса? Мне просто интересно, как использовать RemoveRange в гигантском списке (скажем, 5000 элементов), чтобы удалить f.e. только последние 2 из них.Как работает метод RemoveRange() в списке <>?

Если это делает копию, есть ли способ изменить некоторую внутреннюю переменную, которая задает размер списка (и обрабатывать остальную часть выделенных элементов как мусор)?

Мне удалось найти информацию о том, что это алгоритм сложности O (n), но я не уверен, что «n» в этом случае является размером списка или количеством элементов для удаления.

Будем рады любому намеку.

+0

http://msdn.microsoft.com/en-gb/library/y33yd2b5.aspx «Этот метод является операцией O (n), где n является Count». «Элементы удалены, и все элементы, следующие за ними в списке , имеют индексы, уменьшенные по счету». http://geekswithblogs.net/BlackRabbitCoder/archive/2012/02/23/c.net-little-wondersndashthe-listlttgt-range-methods.aspx "имейте в виду, что это заставляет остальную часть списка перемещаться вниз до заполнить пробел, который может быть нетривиальным.Тем не менее, это не потребует перераспределения списка, потому что размер потенциально сокращается, а не растет ». –

+1

Приходите, вы считаете, что счет - номер, который нужно удалить. Удаление 2 из списка из десяти займет столько же времени, сколько удаляя 2 из миллиона.Если вы щелкнете по счету в документации, он свяжет счетчик списков. – Paparazzi

+1

@Blam Это неверно, если вы не удаляете его из конца списка. Если вы удаляете из начала списка то это разница между сдвигом 8 предметов в памяти на два элемента или смещением 1999,998 элементов в памяти на два элемента. Эти два не будут равны. – Servy

ответ

10

Что нужно сделать, это взять каждый элемент после окончания диапазона элементов, чтобы удалить и переместить его в списке по количеству предметов, которые были удалены. Что касается показателей производительности, то после окончания диапазона перемещаемых элементов будет отображаться одна копия для каждого элемента. Это означает, что он будет работать лучше всего при удалении с конца (это будет O (1)) и наихудшим при удалении с начала (O (n)).

В качестве примера, рассмотрим следующий список:

index - value 

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

Если мы называем RemoveRange(2, 2) Тогда мы удалим два элемента, начиная с индекса 2, поэтому мы удалим C и D.

Эта означает, что E нужно скопировать в индекс 2, затем F нужно скопировать в индекс 3, а G нужно скопировать в индекс 4. Сразу после удаления последнего элемента для каждого элемента есть одна операция копирования.

Обратите внимание, что из-за того, что вы можете переместить весь блок памяти «вверх» на два, это на практике становится более эффективным, если копировать каждый элемент по отдельности. Память компьютеров намного проще перемещать весь блок памяти на некоторое фиксированное количество байтов, чем перемещать множество небольших разделов памяти в разные произвольные местоположения. Однако он будет иметь такую ​​же асимптотическую сложность.

+0

Это именно то, что я хотел знать, спасибо. – Tarec

13

List<T> - это всего лишь обертка вокруг массива, называемая _items в коде ниже. В массиве может быть больше слотов, чем в элементе списка, поэтому _size используется для отслеживания количества действительных значений. Когда вы делаете RemoveRange(index, count) ...

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

... он копирует элементы из прошлых диапазона в теперь пустое пространство, и очищает старые элементы.

Если вы удаляете диапазон, близкий к началу большого списка, тогда стоимость пропорциональна размеру списка, потому что столько вещей нужно сдвинуть вниз.

Если вы удаляете большой диапазон ближе к концу большого списка, то копирование дешево, но очистка стоит дорого, поэтому стоимость будет пропорциональна размеру удаляемого диапазона.

+1

Не могли бы вы пойти немного глубже, почему расчистка дорого во втором случае? Поскольку я понял, что мы должны очищать только затронутые элементы массива, количество которых не является таким большим, как '_size' или' _items.Length' в случае большого списка. Например, если вы удаляете небольшой диапазон в большом списке около начала или ближе к концу. –

+0

Означает ли это, что я должен использовать 'LinkedList ' Если я знаю, что список будет большим, и я захочу удалить его позже? – Jodrell

+2

@ Джодрек Вероятно, нет. При использовании связанного списка потеря места в памяти приводит к очень низкой производительности даже для простых задач, таких как итерация связанного списка. В то время как значения Big O многих из его операций низки, для связанных списков редко встречаются чистые выигрыши в большинстве практических случаев. – Servy

Смежные вопросы