# теория · шаг 2 из 7
Применяем теорему и условие регулярности
Коротко
Порядок применения: посчитай n^(log_b a), сравни с f(n), назови случай. Для
случая 3 (корень перевешивает) есть добавка - условие регулярности
a·f(n/b) ≤ c·f(n) при некотором c < 1. Оно проверяет, что работа по уровням
и правда убывает геометрически вниз, а не только «в одной точке» больше. У
обычных f (n, n², n·log n) оно выполняется само; помнить о нём надо,
когда f растёт скачками.
Если умеешь применить теорему во всех трёх случаях и знаешь, зачем нужно условие регулярности, листай до «Теперь сам».
Как думаешь, всегда ли «корень больше» значит Θ(f(n))
В случае 3 работа f(n) наверху больше числа листьев, и хочется сказать: раз
корень дороже всех, ответ Θ(f(n)). Почти так - но с оговоркой. «Корень дороже
листьев» сравнивает только два края дерева. А вдруг работа по уровням убывает вниз
так медленно, что средние уровни в сумме перевесят корень? Чтобы этого не
случилось, теорема требует отдельную проверку - условие регулярности.
На что это похоже
Это как проверить, что долг гасится всерьёз, а не только «первый платёж крупный».
Если каждый следующий слой работы составляет какую-то постоянную долю c < 1 от
предыдущего (пусть даже 0.9), сумма всех слоёв - геометрический ряд, и его
определяет первый слой, корень. А если слои убывают еле-еле, их набирается много, и «крупный первый
платёж» тонет в хвосте. Условие регулярности - это и есть «каждый слой заметно
меньше предыдущего».
Механизм: три шага и проверка регулярности
Порядок один и тот же.
- Выпиши
a,b,f(n). Посчитай водоразделn^(log_b a). - Сравни
f(n)сn^(log_b a)- кто полиномиально больше (на множительn^ε). - Назови случай и выпиши ответ.
Для случая 3 добавь шаг 4: проверь a·f(n/b) ≤ c·f(n) при каком-нибудь
постоянном c < 1. Смысл: a·f(n/b) - это суммарная работа СЛЕДУЮЩЕГО уровня
вниз (там a вызовов размера n/b). Условие говорит, что уровень ниже стоит не
больше доли c от текущего. Значит по уровням работа падает геометрически, весь
ряд сходится к первому слагаемому, и ответ Θ(f(n)) - работа корня.
Правило
Схема применения: n^(log_b a) → сравнить с f(n) → случай. В случае 3
дополнительно проверить регулярность a·f(n/b) ≤ c·f(n), c < 1. Для
f(n) = nᵏ условие выполняется всегда, когда случай 3 вообще подходит по
степеням, - его проверяют формально, а спотыкаются на нём только специально
подобранные f.
Разбор: случай 1, листья перевешивают
T(n) = 8·T(n/2) + n². Здесь a = 8, b = 2, f(n) = n². Водораздел:
n^(log_2 8) = n³. Сравниваем f(n) = n² с n³: работа одного вызова вне рекурсии полиномиально
МЕНЬШЕ числа листьев (на множитель n, то есть ε = 1). Случай 1, решают листья,
ответ Θ(n³). Смыслом: восемь вызовов при делении лишь пополам - дерево очень
широкое, листьев n³, и квадратичная работа наверху рядом с ними ничтожна.
Разбор: случай 3, корень перевешивает, и регулярность
T(n) = 3·T(n/4) + n. Здесь a = 3, b = 4, f(n) = n. Водораздел:
n^p, где p = log_4 3 ≈ 0,79248. Сравниваем f(n) = n с n^p:
работа корня полиномиально БОЛЬШЕ, отношение равно n^(1−p), где 1−p > 0. Похоже на случай 3 - проверим регулярность:
a·f(n/b) = 3·(n/4) = 0.75·n, а c·f(n) = c·n. Неравенство 0.75·n ≤ c·n
держится при c = 0.75 < 1. Условие выполнено, случай 3 подтверждён, ответ
Θ(f(n)) = Θ(n). Три вызова на входе вчетверо меньше - дерево узкое, работы вниз
всё меньше, и линейная работа корня всё и решает.
Разбор: случай 2, всё уравновешено
T(n) = 2·T(n/2) + n (сортировка слиянием). a = 2, b = 2, f(n) = n.
Водораздел n^(log_2 2) = n. Работа корня n того же порядка, что число
листьев n, - случай 2. Ответ Θ(n^(log_b a)·log n) = Θ(n·log n). Здесь ни
листья, ни корень не перевешивают, поэтому к n добавляется множитель log n от
числа уровней - в точности то, что дерево показывало в прошлой главе.
Что ломается без этого
Две ошибки. Объявить случай 3, не проверив регулярность, - обычно ответ верный,
но на подстроенных f (например f(n) = n²·sin²n + n) регулярность рвётся, и
Θ(f(n)) неверно. И перепутать направление: a·f(n/b) - это уровень ВНИЗ (вход
меньше в b раз), а не вверх; подставлять надо n/b, а не n·b.
Зачем это в работе
Случай 3 с регулярностью - это про алгоритмы, где основная работа наверху, на
неделёном входе: T(n) = 2·T(n/2) + n² (ответ Θ(n²)) - вся цена в квадратичной
склейке, рекурсия дёшева. Знать, что решает корень, важно для оптимизации: ускорять
надо f(n), а не рекурсивную часть - на неё время всё равно почти не уходит. Это
прямое указание, какую строчку кода профилировать.
Теперь сам
Реши теоремой: T(n) = 2·T(n/2) + n³. Определи случай, ответ и, если нужно,
проверь регулярность.
Ответ. a = 2, b = 2, f(n) = n³. Водораздел n^(log_2 2) = n. Работа
корня n³ полиномиально больше n (на n²) - случай 3. Регулярность:
a·f(n/b) = 2·(n/2)³ = 2·n³/8 = n³/4, а c·f(n) = c·n³; неравенство
n³/4 ≤ c·n³ держится при c = 1/4 < 1. Условие выполнено, ответ
Θ(f(n)) = Θ(n³). Кубическая работа на неделёном входе перевешивает всё дерево.
Главное
Применяют теорему по шагам: n^(log_b a) → сравнить с f(n) → назвать случай.
Случай 1 (f полиномиально меньше) - Θ(n^(log_b a)); случай 2 (поровну) -
Θ(n^(log_b a)·log n); случай 3 (f полиномиально больше) - Θ(f(n)), но лишь при условии
регулярности a·f(n/b) ≤ c·f(n), c < 1. Регулярность проверяет, что работа
по уровням убывает геометрически вниз, и тогда её сумму задаёт корень. Для
степенных f оно выполняется, когда показатель подходит под случай 3.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий