2. Основными характеристиками алгоритма,
рассматриваемыми при его анализе, являются
временная сложность и емкостная сложность.
Они позволяют оценить требуемый объем
памяти и время исполнения алгоритма
соответственно.
В настоящее время большее внимание, как
правило, уделяется временной сложности
алгоритмов.
А на ранних этапах развития компьютеров при
ограниченных объемах компьютерной памяти
(как внешней, так и внутренней) анализ
емкостной сложности носил принципиальный
характер.
3. Все алгоритмы разделяются на такие, которым достаточно
ограниченной памяти, и те, которым нужно
дополнительное пространство.
Предположим, например, что мы записываем вещественное число
в интервале от -10 до +10, имеющее один десятичный знак
после запятой. При записи в виде вещественного числа
большинство компьютеров потратит от 4 до 8 байтов памяти,
однако если предварительно умножить число на 10, то мы
получим целое число в интервале от -100 до +100, и для его
хранения выделяется всего один байт. По сравнению с первым
вариантом экономия составляет от 3 до 7 байтов. Программа, в
которой сохраняется 1000 таких чисел, экономит от 3000 до 7000
байтов. Если принять во внимание, что еще недавно (в начале
80-х годов прошлого века) у компьютеров была память объемом
лишь 65536 байтов (64 К), экономия получается существенной.
Именно эта необходимость экономить память наряду с
долголетием компьютерных программ привела к проблеме 2000го года. Если программа использует много различных дат, то
половину места для записи года можно сэкономить, сохраняя
значение 99 вместо 1999. К тому же авторы программ не
предполагали в 80-х годах, что их продукция доживет до 2000-го
года.
4. Некоторую новую ноту внесло недавнее
распространение карманных компьютеров (PDA –
personal digital assistant). У типичного такого
устройства от 2 до 8 мегабайт на все про все – и на
данные, и на программы. И поэтому разработка
маленьких программ, обеспечивающих компактное
хранение данных, становится критической. То же
самое можно отнести и к программам для других
мобильных устройств, выполненным на базе
микроконтроллеров (например, мобильные
телефоны).
Таким образом, в какой-то степени анализ емкостной
сложности алгоритмов является актуальным и в
настоящее время. При этом необходимо учитывать
«правило рычага», которое заключается в том, что в
общем случае, «выигрывая в памяти»,
«проигрывают во времени», и наоборот.
5. Например, на рис. приведены два
алгоритма, решающих одну и ту же задачу
обмена значений двух переменных (эта
задача очень часто используется на
практике). Первый алгоритм (а) обходится
без дополнительной памяти, но требует
больше времени, на исполнение (он
применяет операции присваивания,
сложения и вычитания). Второй алгоритм
(б) использует дополнительную
переменную (т.е. дополнительную
память), но при этом использует только
операцию присваивания (т.е. выполняется
быстрее).
7. 8. Использование
рекуррентных соотношений
для анализа рекурсивных
алгоритмов
Многие алгоритмы основаны на принципе
рекурсивного разбиения большой задачи
на меньшие, когда решения подзадач
используются для решения исходной
задачи.
Рекурсивное разбиение алгоритма
напрямую проявляется в его анализе.
8. Например, время выполнения подобных алгоритмов
определяется величиной и номером подзадачи, а
также временем, необходимым для разбиения
задачи. Математически зависимость времени
выполнения алгоритма для ввода величиной N от
времени выполнения при меньшем количестве
вводов легко задается с помощью рекуррентных
соотношений. Такие формулы точно описывают
производительность алгоритмов: для вычисления
времени выполнения необходимо решить эти
рекурсии.
Рекуррентные соотношения на сложность алгоритма
выводятся непосредственно из вида алгоритма,
однако с их помощью нельзя быстро вычислить эту
сложность. Для этого следует привести
рекуррентные соотношения к так называемому
замкнутому виду, отказавшись от их рекуррентной
природы. Производится такое приведение
посредством последовательных подстановок,
позволяющих уловить общий принцип.
9. Пример 1. В рекурсивной программе, где
при каждой итерации цикла количество
вводов уменьшается на единицу,
возникает следующее рекуррентное
соотношение: CN = CN – 1 + N, где N ≥ 2 и
C1 = 1.
Решение: CN порядка N2 / 2. Для решения
рекурсии ее можно раскрыть, применяя
саму к себе следующим образом:
CN = CN – 1 + N = CN – 2 + (N – 1) + N = CN
– 3 + (N – 2) + (N – 1) + N = …
= C1 + 2 + … + (N – 2) + (N – 1) + N = 1 + 2 +
… + (N – 2) + (N – 1) + N =
= N(N + 1) / 2.
10. Пример 2. В рекурсивной программе, где на каждом шаге
количество вводов уменьшается вдвое, возникает
следующее рекуррентное соотношение: CN = CN / 2 + 1,
где N ≥ 2 и C1 = 1.
Решение: CN порядка log2 N. Из написанного следует, что
это уравнение бессмысленно за исключением случая,
когда N четно или же предполагается, что N /2 является
целочисленным делением. Сейчас предположим, что N =
2n, чтобы рекурсия была всегда определена. Тогда
рекурсию еще проще раскрыть, чем в предыдущем
случае:
CN = CN / 2 + 1 = CN / 4 + 1 + 1 = CN / 8 + 1 + 1 + 1 = … = C1
+ n = 1 + n = n + 1.
Точное решение для любого N зависит от интерпретации
N/2. Если N/2 представляет собой N/2, тогда существует
очень простое решение: CN – это количество бит в
двоичном представлении числа N.
11. Пример 3. В рекурсивной программе, где
количество вводов уменьшается вдвое, но
необходимо проверить каждый элемент,
возникает следующее рекуррентное
соотношение: CN = CN / 2 + N, где N ≥ 2 и C1 =
0.
Решение: CN порядка 2N. Рекурсия раскрывается
в сумму N + N/2 + N/4 + N/8 + ... . (Как и в
примере 2, рекуррентное соотношение
определено точно только в том случае, если N
является степенью числа 2). Если данная
последовательность бесконечна, то сумма
простой геометрической прогрессии равна 2N.
Поскольку мы используем целочисленное
деление и останавливаемся на 1, данное
значение является приближением к точному
ответу. В точном решении используются
свойства двоичного представления числа N.