Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
kernigan_paik.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.91 Mб
Скачать

2.5. "О большое"

Мы описывали трудоемкость алгоритма в зависимости от п, количе­ства входных элементов. Поиск в неотсортированных данных занимает время, пропорциональное я; при использовании двоичного поиска по отсортированным данным время будет пропорционально log п. Время сортировки пропорционально п2 или п log п.

Нам нужно как-то уточнить эти высказывания, при этом абстрагиру­ясь от таких деталей, как скорость процессора и качество компилятора (и программиста). Хотелось бы сравнивать время работы и затраты па­мяти алгоритмов вне зависимости от языка программирования, компи­лятора, архитектуры компьютера, скорости процессора, загруженности системы и других сложных факторов.

Для этой цели существует стандартная форма записи, которая называ­ется "О большое". Основной параметр этой записи — п, размер входных данных, а сложность или время работы алгоритма выражается как фун­кция от п. "О" — от английского order, то есть порядок. Например, фраза "Двоичный поиск имеет сложность O(logn)" означает, что для поиска в массиве из п элементов требуется порядка log п действий. Запись O(f(n)) предусматривает, что при достаточно больших п время выполне­ния пропорционально f(n), не быстрее, например, О(п2) или 0(п log п). Асимптотические оценки вроде этой полезны при теоретическом анализе и грубом сравнении алгоритмов, однако на практике разница в деталях может иметь большое значение. Например, алгоритм класса O(n2) с ма­лым количеством дополнительных вычислений для малых п может ра­ботать быстрее, чем сложный алгоритм класса O(nlog п), однако при достаточно большом п алгоритм с медленнее возрастающей функцией поведения неизбежно будет работать быстрее.

Нам нужно различать также случаи наихудшего и ожидаемого пове­дения. Трудно строго определить, что такое "ожидаемое" поведение, потому что определение зависит от наших предположений о возмож­ных входных данных. Обычно мы можем точно указать самый плохой случай, хотя иногда и здесь можно ошибиться. Для quicksort в самом плохом случае время работы растет как O(n2), а среднее ("ожидаемое") время — как O(п log п). Если каждый раз аккуратно выбирать элемент-разделитель, то мы можем свести вероятность квадратичного (то есть O(n2)) поведения практически к нулю; хорошо реализованная quicksort действительно обычно ведет себя как О(п log п). Вот основные случаи:

Запись

Название времени

Пример

O(1)

Константное

Индексирование массива

O(log п)

Логарифмическое

Двоичный поиск

O(п)

Линейное

Сравнение строк

O(n log n)

и log и

Quicksort

O(п2)

Квадратичное

Простые методы сортировки

O(п3)

Кубическое

Перемножение матриц

O (2n)

Экспоненциальное

Перебор всех подмножеств

Доступ к элементу в массиве — операция, работающая за константное (O(1)) время. Алгоритм, за каждый шаг отсеивающий половину вход­ных данных, как двоичный поиск, обычно займет время O(log п). Срав­нение двух строк длиной в п символов с помощью strcmp займет O(п). Традиционный алгоритм перемножения двух квадратных матриц по­рядка n занимает О(n3), поскольку каждый элемент получается в резуль­тате перемножения и пар чисел и суммирования результатов, а всего элементов n2.

Экспоненциальное время работы алгоритма обычно является резуль­татом перебора всех вариантов: у множества из п элементов — 2n различ­ных подмножеств, поэтому алгоритм, которому надо пройтись по всем подмножествам, будет выполняться за время O(2n), то есть будет экспо­ненциальным. Экспоненциальные алгоритмы обычно слишком долго работают, если только п не очень мало, поскольку добавление одного элемента удваивает время работы алгоритма. К сожалению, существует много задач, таких как, например, знаменитая "задача коммивояжера", для которых известны только экспоненциальные решения. Когда задача такова, часто вместо точных решений берут алгоритмы, находящие не­которое приближение к ответу.

Упражнение 2-3

Каковы входные данные для алгоритма quicksort, которые заставля­ют его работать медленнее всего, как в наихудшем случае? Попробуйте найти несколько наборов данных, сильно замедляющих библиотечную версию алгоритма. Автоматизируйте процесс, чтобы вы легко могли за давать параметры и проводить большое число экспериментов.

Упражнение 2-4

Придумайте и реализуйте алгоритм, который будет сортировать мас­сив из п целых как можно медленнее. Только напишите его честно: алго­ритм должен постепенно прогрессировать и в конце концов завершить­ся, и ваша реализация не должна использовать всяческие трюки вроде лишних пустых циклов. Какова получилась сложность вашего алгоритма как функция от n?

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]