1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6

# теория · шаг 2 из 6

Θ и Ω: зажать с двух сторон

Коротко

O даёт только потолок, поэтому O(n²) честно, но нестрого и для линии. Ω(g) - зеркальное понятие: пол, f растёт не медленнее g. Θ(g) - и пол, и потолок сразу: f зажата между c₁·g и c₂·g, то есть растёт ровно как g. f = Θ(g) тогда и только тогда, когда одновременно f = O(g) и f = Ω(g). Именно Θ и называют «порядком роста» точно.

Если знаешь определения Ω и Θ и почему Θ = O и Ω одновременно - листай до «Теперь сам».

Как думаешь, чем плох потолок без пола

В прошлом уроке вышло, что n = O(n²) - истина. Но сказать про линейный алгоритм «он работает за O(n²)» - всё равно что сказать «дорога займёт не больше суток», когда едешь двадцать минут: формально верно, а по делу бесполезно. O разрешает завысить оценку сколько угодно. Чтобы оценка была честной - не завышенной, - к потолку нужен пол.

На что это похоже

O - потолок над функцией, Ω - пол под ней, Θ - коридор из двух стен сразу. Функция, зажатая в коридоре Θ(g), вынуждена идти вплотную к g: и не выше верхней стены, и не ниже нижней, только обе стены - это g с разными множителями. Отсюда и смысл: Θ(g) - это «растёт ровно как g», а не «не быстрее» или «не медленнее».

Механизм: определения Ω и Θ

f(n) = Ω(g(n)), если существуют c > 0 и n₀, такие что

c·g(n) ≤ f(n)   для всех n ≥ n₀

Это зеркало O: там f была снизу от c·g, здесь - сверху. Ω говорит «f растёт не медленнее g».

f(n) = Θ(g(n)), если существуют c₁ > 0, c₂ > 0 и n₀, такие что

c₁·g(n) ≤ f(n) ≤ c₂·g(n)   для всех n ≥ n₀

f зажата между двумя копиями g с разными множителями - «в коридоре». Отсюда главная связь: f = Θ(g) в точности тогда, когда f = O(g) И f = Ω(g). Верхняя половина коридора - это O (потолок c₂·g), нижняя - Ω (пол c₁·g). Есть обе - есть Θ; нет хотя бы одной - Θ нет.

Правило

f = Θ(g) ⟺ f = O(g) и f = Ω(g). Чтобы доказать Θ, докажи обе границы: сверху (нашёл c₂, n₀: f ≤ c₂·g) и снизу (нашёл c₁, n₀: f ≥ c₁·g). Θ - самое сильное из трёх утверждений: из него следуют и O, и Ω, а из них по отдельности Θ не следует.

Разбор: 3n² + 500n + 2000 = Θ(n²)

Потолок уже доказан в прошлом уроке: f = O(n²) при c₂ = 4, n₀ = 505. Осталось дно. Ω(n²) требует c₁·n² ≤ 3n² + 500n + 2000. Возьмём c₁ = 3: неравенство 3n² ≤ 3n² + 500n + 2000 верно для всех n ≥ 0, ведь справа то же 3n² плюс неотрицательные слагаемые. Значит f = Ω(n²) при c₁ = 3, n₀ = 1. Обе границы есть - f = Θ(n²). Определению Θ нужен один порог n₀ на оба неравенства сразу; берут больший из двух - здесь n₀ = 505, с него держатся и дно, и потолок. Многочлен (сумма степеней n с числовыми множителями, как 3n² + 500n + 2000) всегда Θ от своего старшего члена: потолок берёт множитель побольше, дно - сам множитель старшего члена.

Коридор видно и в числах. Возьмём n = 505: старший член n² = 255 025, а сама f(505) = 3·255025 + 500·505 + 2000 = 1 019 575. Нижняя стена c₁·n² = 3·255025 = 765 075, верхняя c₂·n² = 4·255025 = 1 020 100. Значение зажато между ними: 765 075 ≤ 1 019 575 ≤ 1 020 100. И чем больше n, тем плотнее f прижимается к нижней стене 3n²: младшие слагаемые тают, множитель f стремится к трём. Верхняя стена с запасом c₂ = 4 держится про запас, на случай разгона.

Разбор: почему у алгоритма не всегда есть Θ

Сортировка вставками в ХУДШЕМ случае делает Θ(n²) действий: и не больше (O(n²) - каждый круг сдвигает не весь префикс), и не меньше (Ω(n²) - на обратно отсортированном входе сдвигает именно весь). А вот про сортировку вставками ВООБЩЕ, без указания случая, Θ назвать нельзя: на уже отсортированном входе она делает линию, на обратном - квадрат. Одной функции, зажатой с двух сторон, тут нет - есть разброс от Ω(n) (быстрее линии не бывает, весь вход надо прочесть) до O(n²). Поэтому Θ вешают на конкретный случай, а не на алгоритм целиком.

Что ломается без этого

Главная путаница - лепить Θ туда, где честно только O. «Быстрая сортировка - это Θ(n·log n)» - неверно без оговорки: в худшем случае она Θ(n²), а Θ(n·log n) - это её средний и лучший случаи. Правильно: «в среднем Θ(n·log n), в худшем O(n²)». Вторая ошибка обратная - всегда писать O из осторожности, даже когда известна и нижняя граница: тогда теряется информация, O(2ⁿ) у линейного алгоритма формально верно и совершенно бесполезно.

Зачем это в работе

Θ - это честное сравнение алгоритмов. Когда в статье пишут «наш метод Θ(n·log n), прежний был Θ(n²)», это утверждение с двух сторон: новый и не медленнее n·log n (иначе не о чем говорить), и не быстрее (обещание, которое держат). O уместно там, где известна только верхняя граница - например, для гарантии «не хуже, чем»: SLA обещает O, а не Θ, потому что клиенту важен потолок, а не то, что бывает быстрее.

Теперь сам

Докажи, что T(n) = 6n + 3 = Θ(n). Что нужно предъявить и в каком количестве?

Ответ. Нужны обе границы. Потолок (O): 6n + 3 = O(n) при c₂ = 7, n₀ = 3 (6n + 3 ≤ 7n ⟺ 3 ≤ n). Дно (Ω): 6n + 3 = Ω(n) при c₁ = 6, n₀ = 1 (6n ≤ 6n + 3 всегда). Обе границы есть, значит 6n + 3 = Θ(n). Предъявить надо две пары множителей (c₁ для дна, c₂ для потолка) и порог n₀, дальше которого держатся оба неравенства.

Главное

Ω(g) - пол: f ≥ c·g с какого-то n₀, «не медленнее g». Θ(g) - коридор: c₁·g ≤ f ≤ c₂·g, «ровно как g». f = Θ(g) ⟺ f = O(g) и f = Ω(g), поэтому Θ доказывают двумя границами. O - когда известен только потолок; Θ - когда известны обе стены. У алгоритма Θ есть лишь для фиксированного случая: если лучший и худший случаи разного порядка, единой Θ нет.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.