Big O и коллекции .NET

↑ 8.5 Алгоритмы и структуры данных на C♯ · → Следующая

Желательно~3 мин чтенияУровень: senior

Зачем это на собесе

Оценка сложности и выбор коллекции — база любой алгоритмической задачи.

Объяснение

Big O описывает рост времени/памяти при увеличении входа n (в худшем случае, без констант).

КлассПримерn = 10⁶
O(1)доступ по индексу, Dictionary1
O(log n)бинарный поиск, SortedSet20
O(n)линейный проход10⁶
O(n log n)эффективная сортировка2·10⁷
O(n²)вложенные циклы10¹² (неприемлемо)
O(2ⁿ), O(n!)перебор подмножеств/перестановоктолько для малых n

Коллекции .NET:

КоллекцияДоступ/поискВставкаУдалениеЗаметки
T[]O(1) по индексу, O(n) поиск——фиксированный размер
List<T>O(1) по индексуO(1) в конец амортиз., O(n) в серединуO(n)динамический массив
LinkedList<T>O(n)O(1) при известном узлеO(1) при известном узлередко нужен
Dictionary<K,V>O(1) средн.O(1)O(1)хэш-таблица, порядок не гарантирован
HashSet<T>O(1)O(1)O(1)уникальность
SortedDictionary/SortedSetO(log n)O(log n)O(log n)красно-чёрное дерево
Queue<T>/Stack<T>—O(1)O(1)FIFO / LIFO
PriorityQueue<T,P>Peek O(1)O(log n)O(log n)двоичная куча
ImmutableXкопирование при изменении

Амортизированная сложность: добавление в List<T> в среднем O(1), хотя иногда O(n) при расширении массива (удвоение).

Пространственная сложность: дополнительная память алгоритма (рекурсия — глубина стека).

Нюансы и подводные камни

  • Константы важны на практике: O(n) с тяжёлым телом может быть медленнее O(n log n) на малых n.
  • Contains у List<T> — O(n): для частых проверок используйте HashSet.
  • string += в цикле — O(n²) из-за копирования.
  • Хэш-коллизии и плохой GetHashCode вырождают Dictionary в O(n).
  • LINQ Count() на IEnumerable может перечислять всё.

Практика

  1. Определите сложность кода из 5 фрагментов с вложенными циклами.
  2. Замените List.Contains на HashSet и измерьте.
  3. Выберите коллекцию для очереди задач по приоритету.

Вопросы с ответами

Связанные темы