2. Все задачи делят на следующие три класса: Р,
NP и NPC.
Класс Р состоит из задач, разрешимых в течение
полиномиального времени работы. Точнее
говоря — это задачи, которые можно решить
за время O(nk), где k – некоторая константа, a
n – размер входных данных задачи.
Класс NP состоит из задач, решения которых
(полученные с помощью некоторых
алгоритмов) поддаются проверке в течение
полиномиального времени. Имеется в виду,
что если получено «оптимальное» решение, то
в течение времени, полиномиальным образом
зависящего от размера входных данных
задачи, можно проверить корректность его
решения.
3. Любая задача класса Р принадлежит классу
NP, т.е. Р ⊆ NP. Однако остается открытым
вопрос, является ли Р строгим подмножеством
NP.
Задача принадлежит классу NPC (такие задачи
называются NP-полными – NP-complete), если
она принадлежит классу NP и является такой
же «сложной», как и любая задача из класса
NP, т.е. к ней полиномиально должны
сводиться все задачи из класса NP. Это
значит, что если любую NP-полную задачу
можно решить в течение полиномиального
времени, то для каждой задачи из класса NP
существует алгоритм с полиномиальным
временем работы.
4. Для практических целей можно выделить также еще два
класса задач.
Экспоненциальной по природе считается задача
сложностью не менее порядка xn, где x – константа
или полином от n. Экспоненциальные задачи относят к
классу E. Соответственно, и алгоритмы, в оценку
сложности которых n входит в показатель степени,
относятся к экспоненциальным алгоритмам. При
небольших значениях n экспоненциальный алгоритм
может быть даже менее сложным, чем
полиномиальный. Различие между этими типами
алгоритмов весьма велико и проявляется при больших
значениях n.
Особую группу по значениям сложности, близким к
полиномиальным, составляют задачи (и
соответственно алгоритмы), сложность которых
является полиномиальной функцией от logn (поскольку
logn растет медленнее, чем n).
5. 6. Эмпирические измерения
характеристик выполнения
программы
Анализ алгоритмов должен служить практической
цели разработки программ.
Правильно разработанные программы на
реальном языке, например C++, представляют
собой эффективные методы выражения
алгоритмов.
На практике бывает необходимо описывать
алгоритмы и уделять внимание их
динамическим свойствам экспериментальным
путем.
6. При анализе каждого алгоритма уделяется
внимание, в основном, существенным
характеристикам производительности
алгоритма. Предполагается, что главный
интерес вызывают наиболее простые алгоритмы
с наилучшими показателями
производительности.
Для эффективного использования алгоритмов,
если нашей целью является решение огромной
задачи, которую нельзя решить другим
способом, или если цель заключается в
эффективной реализации важной части
системы, нам требуется понимание
характеристик производительности алгоритмов.
Формирование такого понимания и является
целью анализа алгоритмов.
7. Один из первых шагов для продвижения вперед в
понимании производительности алгоритмов –
это эмпирический анализ.
Если есть два алгоритма для решения одной
задачи, то, запустив оба и определив, который
выполняется дольше, мы получаем
необходимую информацию.
Первая проблема, возникающая перед
исследователями в эмпирическом анализе – это
разработка корректной и полной реализации.
Обычно требуется либо с помощью анализа, либо
путем экспериментирования с похожими
программами, установить некоторый признак,
насколько эффективной может быть программа,
до того как тратить усилия на ее реализацию.
8. Вторая проблема– это определение
природы входных данных и других
факторов, оказывающих прямое влияние
на производимые эксперименты.
Обычно существуют три основных
возможности: реальные данные,
случайные данные и ошибочные данные.
Реальные данные позволяют точно
измерить параметры используемой
программы; случайные данные
гарантируют, что наши эксперименты
тестируют алгоритм, а не данные;
ошибочные данные гарантируют, что наши
программы могут воспринимать любой
9. Проблема определения, какие данные
необходимо использовать для сравнения
алгоритмов, возникает также и при
анализе алгоритмов. При сравнении
различных реализаций легко допустить
ошибки, особенно, если в игру вступают
разные машины, компиляторы или
системы, либо гигантские программы с
плохо охарактеризованным вводом.
Принципиальная опасность при
эмпирическом сравнении программ таится
в том, что код для одной реализации
может быть создан более тщательно, чем
для другой.
10. Один из подходов заключается в построении
алгоритмов за счет внесения небольших
изменений в алгоритмы, существующие для
данной задачи, поэтому сравнительное изучение
просто необходимо. Для этого можно
определить важнейшие абстрактные операции и
сравнивать алгоритмы на основе того, как они
используют такие операции.
Возможно, наиболее распространенной ошибкой
при выборе алгоритма является упущение
характеристик производительности.
Возможно, вторая наиболее распространенная
ошибка при выборе алгоритма, – уделять
слишком много внимания характеристикам его
производительности.
11. Невозможно провести эмпирические тесты
для программы, которая еще не написана,
но мы можем проанализировать свойства
программы и оценить потенциальную
эффективность предлагаемого
улучшения.