Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Билеты по проге.docx
Скачиваний:
5
Добавлен:
01.07.2025
Размер:
630.61 Кб
Скачать

Дополнительно (то же самое)

При анализе эффективности одинаково важны как время выполнения алгоритма, так и занимаемая им память.

Анализ эффективности алгоритмов не должен зависеть от:

  1. От их реализации, поскольку они очень сильно зависят от стиля программирования и не позволяют определить, какой из алгоритмов эффективнее.

  2. От особенностей конкретного компьютера.

  3. От выбора конкретных данных.

Чтобы преодолеть эти трудности, были разработаны математические методы анализа алгоритмов.

Оценка эффективности алгоритма

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

Пример: вложенные циклы.

Что конкретно нужно знать о быстродействии алгоритма? Важнее всего знать, насколько быстро возрастает время его выполнения с увеличением размера задачи:

Время выполнения алгоритма А прямо пропорционально n2.

Время выполнения алгоритма В прямо пропорционально n.

По этим утверждениям нельзя определить, сколько именно времени выполняется алгоритм А или В. Главное, что при решении больших задач алгоритм В работает намного быстрее.

Временная сложность алгоритма

Допустим, выполняется следующее утверждение: время выполнения алгоритма А прямо пропорционально функции f(n). В таких случаях говорят, что алгоритм А имеет порядок f(n), обозначающийся как O(f(n)). Функция f(n) называется временной сложностью алгоритма.

Некоторые свойства временной сложности алгоритма (функции f(n) )

  1. При оценке сложности алгоритма можно учитывать только старшую степень. Например, если алгоритм имеет сложность O(n3 + 4*n2 + 3*n), он имеет порядок O(n3).

  2. При оценке сложности алгоритма можно игнорировать множитель при старшей степени.

  3. Функции, описывающие сложность алгоритма, можно складывать. Например, если алгоритм имеет сложность О(n2) +О(n), то говорят, что он имеет сложность О(n2+n).

При оценке эффективности алгоритма нужно оценить лишь порядок его сложности.

Наихудший и средний варианты

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

Анализ среднего варианта позволяет оценить среднее время выполнения алгоритма при решении задачи размера n. Как правило, анализ среднего варианта выполнить намного сложнее, чем анализ наихудшего варианта. Одна из трудностей заключается в определении вероятностей появления разных задач одинаковой размерности. Вторая трудность заключается в вычислении распределений разных значений. Анализ наихудшего варианта легче поддается вычислениям и поэтому выполняется намного чаще.

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

Замечание! Анализ сложности алгоритмов ориентируется на большие задачи. Если максимальный размер задачи невелик, время выполнения алгоритмов разной сложности не будет значительно отличаться. Если заранее известно, что размер задачи никогда не будет больше, анализ эффективности алгоритмов можно не проводить. В таких случаях следует выбрать наиболее простой алгоритм, запрограммировать его и протестировать.

Следует стремиться к равновесию между быстродействием алгоритма и объемом занимаемой им памяти.

Довольно часто при оценке эффективности алгоритмов нужно отыскать компромисс между быстродействием и занимаемым объемом памяти. Итак, стиль и эффективность алгоритма одинаково важны. Анализ сложности алгоритмов ориентируется на большие задачи.

Фактически при анализе сложности алгоритма неявно предполагается, что он будет применяться для решения больших задач. Сравнение эффективности алгоритмов должно быть сосредоточено на их существенных различиях. При анализе эффективности одинаково важны как время выполнения алгоритма, так и занимаемая им память.

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

1. Как запрограммированы алгоритмы?

Допустим, алгоритм А1 выполняется быстрее, чем алгоритм А2. Это может быть связано с тем, что программа, реализующая алгоритм, просто лучше написана. Следовательно, сравнивая время выполнения программ, вы на самом деле сравниваете реализации алгоритмов, а не сами алгоритмы. Реализации алгоритмов сравнивать бессмысленно, поскольку они очень сильно зависят от стиля программирования и не позволяют определить, какой из алгоритмов эффективнее.

Билет 11. Рекурсия

Рекурсивный объект – объект, частично или полностью определенный через самого себя.

Мощь рекурсии заключается в возможности определить бесконечное множество объектов с помощью конечного утверждения. Можно привести задачу большей размерности к задаче меньшей размерности. Необходимое и достаточное средство для рекурсивной формулировки программы – рекурсивная функция (процедура). Пример – функция расчета факториала: int factr(int n)

{

if(n==1) return(1);

return( factr(n-1)*n); /* рекурсивный вызов */

}

Необходимое и достаточное условие существования рекурсии:

А(n)

{

A(n)

}

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

Общая схема рекурсии такова: void решить задачу (N) {

if (n==1) решение ( ); else {

подготовка решения ( ); решить задачу для (N-1): } }

Что происходит, когда функция F выполняет рекурсивный вызов? Прежде всего, запоминается текущее состояние программы, необходимое для продолжения вычислений, когда управление снова вернется к ней. Затем F с новыми значениями аргументов начинает выполняться заново как бы с новым экземпляром программы. При следующем рекурсивном вызове F всё повторяется и т.д. до тех пор, пока очередной вызов F не приводит к какому-либо тривиальному случаю, разрешаемому без рекурсивных вызовов. Далее, в порядке, обратном тому, в котором запоминалась серия вызовов, производятся возвраты управления. В практических приложениях важно убедиться, что максимальная глубина рекурсивных вызовов не только конечна, но и достаточно мала. В противном случае не избежать переполнения стека - специально организованного участка памяти, где запоминаются отдельные состояния программы-функции.