Почему список(T).Очистить O (N)?

по данным документация MSDN на List<T>.Clear метод:

этот метод является операцией O(n) , где n-количество.

почему O (n)? Я спрашиваю, потому что я бы предположил, что очистка List<T> может быть достигнуто просто путем выделения нового T[] массив. Ни один другой класс не может иметь ссылку на этот массив, поэтому я не вижу вреда в этом подходе.

теперь, может быть, это глупый вопрос... есть выделить T[] сам массив O (n)? По какой-то причине я бы так не подумал; но, может быть, это (мое отсутствие степени C. S. показывает прямо сейчас?). Если это так, я полагаю, что это объяснит это, поскольку, согласно той же документации, приведенной выше, емкость списка остается неизменной, а это означает, что потребуется построить массив равного размера.

(опять же, это не похоже, это может быть правильное объяснение, так как документация должна была сказать "где Н емкости"-не Count*).

Я подозреваемый что этот метод, а не выделение нового массива, обнуляет все элементы текущего; и мне любопытно знать, почему это было бы.

*Ганс Пассант указал в комментарии LukeH это, что документы правильные. Clear только обнуляет элементы, которые были установлены в List<T>; ему не нужно "re-zero" все элементы за этими.

4 ответов


насколько мне известно, текущая реализация просто вызывает Array.Clear внутренние T[] массив, а Array.Clear является процессом O(n). (Как указывает Ханс в комментариях, документы MSDN верны, что n в этом случае является список Count, а не Capacity.)

но, даже если он просто выделил новый T[] массив внутри, это все равно будет o (n) процесс, потому что выделение массива size n включает инициализацию всех n элементы в их нулевое/нулевое / состояние по умолчанию.

конечно, нет ничего, чтобы остановить какой-то внутренний обман, где массив может быть инициализирован длиной 0 или 42 или что угодно, а затем автоматически расширен снова на лету, как требуется, амортизируя общую стоимость O(n).


потому что реализация List<T>.Clear() звонки Array.Clear() в массиве backign списка и в документация этот метод устанавливает все элементы этого массива в null.

Я бы предположил, что причина, по которой существующий массив очищается вместо нового, заключается в том, что команда .NET определила, что было более эффективно очистить существующий массив вместо выделения нового. Выделение нового массива также требует времени / памяти, поэтому это компромисс, который пытается оптимизировать для общих сценариев использования.


List<T>.Clear() звонки Array.Clear() как видно здесь:

public virtual void Clear()
{
    if (this._size > 0)
    {
        Array.Clear(this._items, 0, this._size);
        this._size = 0;
    }
    this._version++;
}

в свою очередь Array.Clear() вызывает внешнюю функцию, которая будет обнулять элементы массива, который является O (n):

[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern void Clear(Array array, int index, int length);

List<T> списки содержат некоторые объекты. Выделение нового List<T> не избавляется от объектов в старом списке, следовательно, это не clear операции.

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

выделение T[] зависит от того, указан ли размер. Если указан размер, то память должна быть выделена для каждого элемент, или, по крайней мере, каждый указатель на этот элемент. Таким образом, это займет O(n). Однако, если мы просто инициализируем указатель для T[], что бы O(1) времени.

П. С. степень КС автоматически не означает, что вы знаете (или помните) этот материал... печально, но это правда. Отсутствие степени CS не вредно на всех.