English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

гость
1 / ?
назад к урокам

Чтение кода для анализа темпов роста

Проверка кода на корректность vs проверка кода на сложность

Проверка кода на корректность ловит логические ошибки: неправильные условия, ошибки на единицу в индексах, пропущенные проверки на null. Проверка кода с учётом сложности ловит другой класс дефектов: код, который работает корректно при N = 100, но растёт катастрофически при N = 100 000.

Паттерн MOAD-0001: list seen O(N²) vs set seen O(N) — одностроковое исправление


Этот урок связан с более глубоким расследованием в курсе unhamming: Недостающая глава: алгоритмическая сложность охватывает Big O в контексте рабочих дефектов, & MOAD-0001: осадочный дефект отображает паттерн на 60+ экосистемах программного обеспечения.


Два эвристических подхода для проверки


Вложенные циклы умножают сложность. Два вложенных цикла по N элементов производят O(N²). Три производят O(N³). При проверке: сначала подсчитайте глубину вложения циклов.


Последовательный контейнер внутри горячего цикла. Любая проверка .contains(), .includes(), .find(), или in list внутри цикла стоит O(N) на проверку. На N итерациях: O(N²) в сумме. Этот паттерн появляется в рабочем коде на десятках экосистем — GHC Haskell компилятор, Python pip, Apache Maven, Rust Cargo, TypeScript, Godot. Одна и та же ошибка, разные кодовые базы.

Проверка: find_duplicates

Проверьте следующую функцию Python на сложность:


def find_duplicates(items):
    seen = []
    duplicates = []
    for item in items:
        if item in seen:
            duplicates.append(item)
        else:
            seen.append(item)
    return duplicates
Выполните проверку кода с учётом сложности: (a) Какова временная сложность этой функции? (b) Почему? Определите точную строку, ответственную за это. (c) Переработайте это в O(N).

MOAD-0001: осадочный дефект

Один и тот же дефект, шестьдесят экосистем

Паттерн if x not in list: list.append(x) внутри цикла появляется — и появлялся — в рабочем коде на десятках экосистем программного обеспечения:


- GHC (Haskell компилятор): решатель зависимостей, O(N²) при N = 50 000 пакетов, сборки в 17 минут

- Python pip: разрешение конфликтов зависимостей

- Apache Maven: дедупликация пути класса

- Rust Cargo: объединение функций

- TypeScript компилятор: разрешение модулей

- Godot / Redot игровой движок: обход графа узлов


Ни одна из этих команд не допустила ошибку. Они написали правильный код при малых N. N вырос. Код затвердел. Паттерн имеет имя: MOAD-0001, осадочный дефект. Осадок: правильный, безвредный в тонких слоях. Со временем слои накапливаются и затвердевают.


Исправление

В каждом случае: замените последовательный контейнер на хеш-контейнер. Одна строка. Нулевое изменение поведения при корректных входах. Ускорение в 100–1 000 раз при реальных N.


Исправление работает, потому что две операции должны оставаться быстрыми:

1. Проверка членства: был ли этот элемент видён раньше?

2. Упорядоченный вывод: вернуть элементы в порядке их появления (иногда требуется, иногда нет).


Множество обрабатывает (1) в O(1). Если (2) также важна, держите отдельный список для упорядоченного вывода и множество для проверки членства. Две структуры данных, каждая делает одну работу.

Ответ рецензенту

Запрос на слияние исправляет MOAD-0001 в функции обхода графа проекта. Рецензент комментирует:


> "Множества не сохраняют порядок вставки — это меняет поведение."

Как вы ответите? Объясните, когда забота рецензента применяется, а когда нет. Предложите решение, которое удовлетворяет обе заботы, когда они конфликтуют.

Паттерн анализа на собеседовании

Ожидаемый формат

Анализ сложности алгоритмов появляется на собеседованиях по разработке программного обеспечения. Сильный ответ следует четырёхчастному паттерну:


1. Сформулируйте текущую сложность — O(?) для времени, O(?) для пространства.

2. Объясните почему — определите конкретную конструкцию, ответственную за это (вложенный цикл, линейное сканирование в цикле, рекурсивное ветвление).

3. Предложите оптимизацию — назовите изменение и структуру данных или алгоритм, который оно вводит.

4. Сформулируйте новую сложность — после исправления, какова временная & пространственная сложность?


Пример:

Код: [функция, которая проверяет членство в списке внутри цикла]
Текущая: O(N²) — `item in seen_list` это O(N) на проверку × N итераций
Оптимизация: замените seen_list на seen_set (хеш-множество)
После: O(N) — проверка членства в множестве это O(1)

Этот навык переносится за пределы собеседований: проверка кода с учётом сложности, дизайн архитектуры, отладка производительности, аудиты безопасности. Любая система, которая обрабатывает входы переменного размера, выигрывает от неё.


Этот урок соединяется дальше с курсом unhamming, который применяет этот точный паттерн к расследованию рабочих дефектов на 60+ проектах с открытым исходным кодом.

Собеседование: анализ has_common_element

Примените четырёхчастный формат собеседования к этой функции:


def has_common_element(list_a, list_b):
    for item in list_a:
        for other in list_b:
            if item == other:
                return True
    return False
Сформулируйте текущую сложность, объясните почему, предложите оптимизацию, сформулируйте новую сложность.