Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
оценка сложности алгоритмов.doc
Скачиваний:
25
Добавлен:
10.07.2019
Размер:
353.28 Кб
Скачать

Билет 26

Вычислительная сложность.

В предыдущем разделе мы ввели понятие алгоритма, определив его как точное предписание, задающее процесс преобразования исходных данных в результаты. Обычно требуется, чтобы алгоритмы обладали следующими пятью свойствами (проверим приведенный в предыдущем разделе алгоритм Евклида на соответствие этим свойствам):

1. Результативность. Алгоритм должен давать некоторый результат. В данном случае этот результат – НОД.

2. Конечность. Работа алгоритма должна заканчиваться за конечное число шагов. Алгоритм Евклида обладает этим свойством, т.к. максимумы из X и Y образуют убывающую последовательность натуральных чисел, не могущую быть бесконечной.

3. Определённость. Все предписания алгоритма должны допускать однозначную трактовку и быть понятными исполнителю (например, компьютеру). Т.е. исполнитель должен обладать средствами выполнения всех инструкций. В данном случае машина должна уметь сравнивать и вычитать натуральные числа .

4. Массовость. Алгоритм должен давать решения целой группы задач, отличающихся исходными данными. Алгоритм Евклида позволяет найти НОД любой пары натуральных чисел.

5. Детерминированность. Многократное применение к одному и тому же набору исходных данных должно давать одинаковый результат. Применительно к алгоритму Евклида это также справедливо.

Но кроме того, огромное значение имеет

6. Эффективность. Все шаги алгоритма должны быть такими, чтобы исполнитель мог выполнить их за конечное время, лежащее в некоторых разумных пределах. И если речь идёт о вычислительной машине, то – в пределах разумных ограничений используемой памяти.

Именно с эффективностью алгоритма интуитивно связано понятие “стоимости“, понимаемой как количественная оценка требуемых для его реализации ресурсов. Более точный смысл понятию стоимости позволяет придать понятие сложности алгоритмов. Оно овеществляет стоимость во времени и в пространстве, позволяет оценить время выполнения и объём требуемой памяти.

Вообще можно сказать, что по мере накопления опыта работы в некоторой области знаний, каждый из нас начинает интуитивно чувствовать, что та или иная задача более или менее трудна, чем другая. Разумеется, такого субъективного, не выраженного количественной мерой понятия как “легче” или “труднее”, нам не достаточно. Как же можно (и можно ли?) определить действительную сложность задачи?

Сложность алгоритма оценивают по его динамическим характеристикам, а не по статическим: например, большая программа может выполняться очень быстро, а короткая – очень долго. На практике сложность алгоритма обычно связывают с основным его параметром, существенно влияющим на количество выполняемых действий. Как правило, это размер массива обрабатываемых данных (размер задачи).

Кроме того, естественно считать критерием качества алгоритма решение наихудшего из возможных случаев его применения.

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

Сложность задачи – это сложность наилучшего алгоритма, известного для ее решения. Поэтому она зависит от уровня развития методов решения. Здесь возникают три принципиальных вопроса:

1. До какого предела можно улучшать данный алгоритм?

2. Ведет ли учет сложности к появлению некоторой классификации задач?

3. Существуют ли методы перехода из одного класса в другой, т.е. от более сложных задач к более простым?

Например, время работы алгоритма, выполняющего только операции чтения и занесения n данных в оперативной памяти, определяется формулой t=an+b, где a – время чтения-записи, b – суммарное время вспомогательных операций. Здесь имеет место линейная зависимость от n, и сложность алгоритма поэтому называется линейной. Коэффициенты a и b неизвестны, но зависят от ЭВМ, транслятора и т.д. Поэтому интересен характер зависимости от основного параметра, говорят о теоретической сложности, учитывая ту функцию от основного параметра, которая определяет сложность. В данном случае это O(n).

Сортировка с помощью прямого обмена ("пузырьковая сортировка") n элементов массива представляет собой следующий процесс: определяется наименьший элемент во всем массиве и производится его обмен с первым элементом; затем определяется наименьший элемент в оставшейся части массива и производится его обмен со вторым элементом и т.д. Значит, всего выполняется n–1 сравнений при поиске первого элемента, n–2 сравнений при поиске второго элемента и т.д.

(n–1)+(n–2)+...+1=(n)/2

Это полином второй степени (говорят, что сложность алгоритма полиномиальна, а в данном случае – квадратична). Для больших n можно считать, что сложность O( ).

Если сложность алгоритма оценивается по уже написанной программе, то вместо числа сравнений вычисляется число повторений внутренних циклов

for k:=1 to n–1 do

begin min:=A [k];

for i:=k+1 to n do

if min>A[i] then min:=A[i];

A[i]:=A[k];

A[k]:=min;

end

Внешний цикл выполняется n–1 раз. Внутренний цикл при каждом повторении внешнего срабатывает в среднем (при равномерном разбросе величин) n/2 раз. Умножив, получаем ту же самую величину.

При больших значениях n за асимптотическую оценку можно взять , т.е. сложность имеет порядок O( ).

Оценками времени работы алгоритма являются максимальное, минимальное и среднее время его выполнения. Они могут совпадать или не совпадать. В приведённой процедуре сортировки они совпадают, а в алгоритме Евклида не совпадают. Максимальное число шагов – циклов очевидно определяется ситуацией вида A=max, B=1. Тогда, если за параметр n взять значение | A–B |, то максимальная оценка сложности – порядка O(n). Но минимальная оценка сложности при A¹B соответствует ситуации A=2B. Результат в этом случае достигается за один шаг, а сложность – O(1) не зависит от n.

"Усовершенствуем" алгоритм Евклида, прекращая его выполнение в том случае, если оказывается, что одно из чисел делится на другое. Тогда это и есть НОД:

X:=A; Y:=B;

while X modY ¹ 0 or YmodX ¹ 0 do

if X>Y then X:=X–Y else Y:=Y–X;

NOD:=min(X, Y)

В нашем примере (см. раздел 3.1) вместо пяти выполнится только один шаг, а в случае равенства одного из двух исходных чисел A и B единице, так же как в случае кратности одного числа другому, преобразования вообще не производятся.

Тем не менее – скорее интуитивно – следует считать среднее значение оценки сложности линейно зависящим от |AB|, хотя достаточно низкий коэффициент можно установить статистически.

Также можно улучшить и алгоритм сортировки, о чем будет сказано далее.

Однако в большом числе задач верхние и нижние оценки совпадают на уровне порядка. Например, оценим сложность алгоритма умножения матриц размера n:

for i:=1 to n do

for j:=1 to n do

begin C[i, j]:=0;

for k:=1 to n do

C[i, j]:=C[i, j]+A[i, k]*B[k, j]

end

Очевидно, что общее количество операций, выполняемых в трех вложенных циклах, пропорционально . И как бы мы ни совершенствовали алгоритм, объективно существует число операций для решения задачи, такое, что верхние и нижние оценки сложности совпадают: O( )=o( ). В целом эта оценка также полиномиальная.

Итак, рассмотрим некоторый алгоритм A. Почти всегда существует параметр n, характеризующий объём его данных. Пусть функция T(n) – время выполнения A. Пусть f – некоторая функция от n. Говорят, что алгоритм A имеет теоретическую (асимптотическую) сложность O(f(n)), если

Если алгоритм выполняется за фиксированное время, не зависящее от размера задачи, говорят, что его сложность равна O(1).

Это определение обобщается в случае, если время выполнения существенно зависит от нескольких параметров. Например, алгоритм, определяющий, входит ли множество m элементов в множество n элементов, может иметь в зависимости от используемых структур данных сложность O(mn) или O(m+n).

Практически время выполнения алгоритма может зависеть от значений данных, как мы видели выше. Время выполнения некоторых алгоритмов сортировки (см. далее) существенно сокращается, если первоначально эти данные частично упорядочены. Чтобы учитывать это, сохраняя возможность анализировать алгоритм независимо от их данных, различают:

Максимальную сложность, определяемую значением Tmax(n) – время выполнения алгоритма, когда выбранный набор n данных порождает наиболее долгое время выполнения алгоритма;

Среднюю сложность, определяемую значением Tср(n) – средним временем выполнения алгоритма, применённого к n произвольным данным.

Эти понятия без труда распространяются на измерение стоимости в единицах объёма памяти: можно говорить о средней и максимальной пространственной сложности.