Введение: O-символика Александр Куликов Онлайн-курс «Алгоритмы: теория и практика. Методы» http://stepic.org/217 Время работы Функция FibArray(n) создать массив F [0 . . . n] F [0] ← 0 F [1] ← 1 для i от 2 до n: F [i] ← F [i − 1] + F [i − 2] вернуть F [n] 2 / 13 Время работы Функция FibArray(n) создать массив F [0 . . . n] F [0] ← 0 F [1] ← 1 для i от 2 до n: F [i] ← F [i − 1] + F [i − 2] вернуть F [n] Функция выполняет 2n + 2 строк кода (4 + 2 · (n − 1)), но действительно ли это отражает время работы алгоритма? 2 / 13 Построчно Разные строки занимают разное время: F [0] ← 0 присваивание 3 / 13 Построчно Разные строки занимают разное время: F [0] ← 0 присваивание для i от 2 до n инкрементирование i (сложение и присваивание) проверка условия 3 / 13 Построчно Разные строки занимают разное время: F [0] ← 0 присваивание для i от 2 до n инкрементирование i (сложение и присваивание) проверка условия создание массива F [0 . . . n] выделение памяти 3 / 13 Построчно Разные строки занимают разное время: F [0] ← 0 присваивание для i от 2 до n инкрементирование i (сложение и присваивание) проверка условия создание массива F [0 . . . n] выделение памяти F [i] ← F [i − 1] + F [i − 2] доступ к элементу сложение (возможно, длинных чисел) присваивание 3 / 13 Точное время работы Точное время работы зависит от многих факторов: тактовая частота процессора архитектура компилятор устройство иерархии памяти 4 / 13 Точное время работы Точное время работы зависит от многих факторов: тактовая частота процессора архитектура компилятор устройство иерархии памяти Необходим способ измерения времени работы, не зависящий от данных факторов. 4 / 13 O-символика Определение Пусть f , g : N → R>0 . Говорим, что f растёт не быстрее g и пишем f (n) = O(g (n)) или f ⪯ g , если существует такая константа c > 0, что f (n) ≤ c · g (n) для всех n ∈ N. 5 / 13 O-символика Определение Пусть f , g : N → R>0 . Говорим, что f растёт не быстрее g и пишем f (n) = O(g (n)) или f ⪯ g , если существует такая константа c > 0, что f (n) ≤ c · g (n) для всех n ∈ N. Пример 3n2 + 5n + 2 = O(n2 ), поскольку при n ≥ 1 выполнено 3n2 + 5n + 2 ≤ 3n2 + 5n2 + 2n2 = 10n2 . 5 / 13 Скорость роста 3n2 + 5n + 2 имеет ту же скорость роста, что и n2 . 10 9 8 7 6 5 4 3 2 1 3n2 +5n+2 n2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 6 / 13 Использования O-символики Мы будем использовать O-символику для оценки времени работы алгоритмов. 7 / 13 Использования O-символики Мы будем использовать O-символику для оценки времени работы алгоритмов. Преимущества: характеризует зависимость времени работы от размера входных данных более простые оценки (O(n2 ) вместо 3n2 + 5n + 2) упрощённый анализ (не думаем, сколько в действительности занимает каждая отдельная операция) не зависит от машины, на которой запускается алгоритм 7 / 13 Использования O-символики Мы будем использовать O-символику для оценки времени работы алгоритмов. Преимущества: характеризует зависимость времени работы от размера входных данных более простые оценки (O(n2 ) вместо 3n2 + 5n + 2) упрощённый анализ (не думаем, сколько в действительности занимает каждая отдельная операция) не зависит от машины, на которой запускается алгоритм Недостатки: O-символика скрывает константные множители, которые на практике могут оказаться очень важными O-символика говорит только про скорость роста 7 / 13 Связанные определения Определение Пусть f , g : N → R>0 . f (n) = Ω(g (n)) и f ⪰ g , если существует положительная константа c, для которой f (n) ≥ c · g (n) (f растёт не медленнее g ) f (n) = Θ(g (n)) и f ≍ g , если f = O(g ) и f = Ω(g ) (f и g имеют одинаковую скорость роста) f (n) = o(g (n)) и f ≺ g , если f (n)/g (n) → 0 при n → ∞ (f растёт медленнее g ). 8 / 13 Общие правила Постоянные множители можно опускать: 2 7n3 = Θ(n3 ), n3 = Θ(n2 ) 9 / 13 Общие правила Постоянные множители можно опускать: 2 7n3 = Θ(n3 ), n3 = Θ(n2 ) Многочлен более высокой степени растёт быстрее: na ≺ nb при a < b √ n = O(n2 ), n2 = O(n4 ), n = O(n) 9 / 13 Общие правила Постоянные множители можно опускать: 2 7n3 = Θ(n3 ), n3 = Θ(n2 ) Многочлен более высокой степени растёт быстрее: na ≺ nb при a < b √ n = O(n2 ), n2 = O(n4 ), n = O(n) Экспонента растёт быстрее многочлена: na ≺ b n √ (a > 0, b > 1): n 5 n = O( 2 ), n2 = O(3n ), n100 = O(1.1n ) 9 / 13 Общие правила Постоянные множители можно опускать: 2 7n3 = Θ(n3 ), n3 = Θ(n2 ) Многочлен более высокой степени растёт быстрее: na ≺ nb при a < b √ n = O(n2 ), n2 = O(n4 ), n = O(n) Экспонента растёт быстрее многочлена: na ≺ b n √ (a > 0, b > 1): n 5 n = O( 2 ), n2 = O(3n ), n100 = O(1.1n ) Многочлен растёт быстрее логарифма: (log n)a ≺ nb √ (a, b > 0): (log n)3 = O( n), n log n = O(n2 ) 9 / 13 Общие правила Постоянные множители можно опускать: 2 7n3 = Θ(n3 ), n3 = Θ(n2 ) Многочлен более высокой степени растёт быстрее: na ≺ nb при a < b √ n = O(n2 ), n2 = O(n4 ), n = O(n) Экспонента растёт быстрее многочлена: na ≺ b n √ (a > 0, b > 1): n 5 n = O( 2 ), n2 = O(3n ), n100 = O(1.1n ) Многочлен растёт быстрее логарифма: (log n)a ≺ nb √ (a, b > 0): (log n)3 = O( n), n log n = O(n2 ) Медленнее растущие слагаемые можно опускать : (f + g = O(max(f , g ))) n2 + n = O(n2 ), 2n + n9 = O(2n ) 9 / 13 Часто используемые функции log n ≺ √ n ≺ n ≺ n log n ≺ n2 ≺ 2n 10 / 13 Часто используемые функции log n ≺ √ n ≺ n ≺ n log n ≺ n2 ≺ 2n 16 14 12 10 8 6 4 2 2 4 6 8 10 Часто используемые функции log n ≺ √ n ≺ n ≺ n log n ≺ n2 ≺ 2n 16 128 14 112 12 96 10 80 8 64 6 48 4 32 2 16 2 4 6 8 10 2 4 6 10 / 13 Время в зависимости от размера входа При скорости 109 операций в секунду n2 2n n = 20 1 сек 1 сек n = 50 1 сек 1 сек n = 102 1 сек 1 сек n = 106 1 сек 1 сек n = 109 1 сек 30 сек 1 сек 1 сек 1 сек 17 мин 30 лет 1 сек 13 дней 4 · 1013 лет 109 104,5 30 n макс n для 1 сек n log n 107 11 / 13 Скорость роста на практике Операция Время работы 12 / 13 Скорость роста на практике Операция создать массив F [0 . . . n] Время работы Θ(n) 12 / 13 Скорость роста на практике Операция создать массив F [0 . . . n] F [0] ← 0 Время работы Θ(n) Θ(1) 12 / 13 Скорость роста на практике Операция создать массив F [0 . . . n] F [0] ← 0 F [1] ← 1 Время работы Θ(n) Θ(1) Θ(1) 12 / 13 Скорость роста на практике Операция создать массив F [0 . . . n] F [0] ← 0 F [1] ← 1 для i от 2 до n: Время работы Θ(n) Θ(1) Θ(1) цикл, Θ(n) итераций 12 / 13 Скорость роста на практике Операция создать массив F [0 . . . n] F [0] ← 0 F [1] ← 1 для i от 2 до n: F [i] ← F [i − 1] + F [i − 2] Время работы Θ(n) Θ(1) Θ(1) цикл, Θ(n) итераций Θ(n) 12 / 13 Скорость роста на практике Операция создать массив F [0 . . . n] F [0] ← 0 F [1] ← 1 для i от 2 до n: F [i] ← F [i − 1] + F [i − 2] вернуть F [n] Время работы Θ(n) Θ(1) Θ(1) цикл, Θ(n) итераций Θ(n) Θ(1) 12 / 13 Скорость роста на практике Операция создать массив F [0 . . . n] F [0] ← 0 F [1] ← 1 для i от 2 до n: F [i] ← F [i − 1] + F [i − 2] вернуть F [n] Время работы Θ(n) Θ(1) Θ(1) цикл, Θ(n) итераций Θ(n) Θ(1) Итого: Θ(n) + Θ(1) + Θ(1) + Θ(n) · Θ(n) + Θ(1) = Θ(n2 ). 12 / 13 Заключение С одной стороны, O-символика позволяет оценить ситуацию в первом приближении, игнорируя ненужные детали. С другой — O-символика заодно игнорирует и некоторые детали, которые на практике оказываются очень важными. 13 / 13