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

4.3. Анализ алгоритмов

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

Клиент судит о программе по ее корректности, легкости использования и эффективности. Легкость использования и корректность программы зависит от процедур разработки и тестирования. На эффективность программы влияет множество факторов, которые включают внутреннюю машинную систему, количество памяти, имеющейся для управления данными и сложность алгоритмов. Эти факторы кратко рассматриваются и затем сосредоточивается внимание на вычислительной сложности алгоритмов. Разрабатываются критерии эффективности, позволяющие измерять эффективность какого-либо алгоритма в терминах размера коллекции. Критерии не зависят от определенной машинной системы и измеряют абстрактные характеристики эффективности алгоритмов. Для создания численной меры эффективности используется нотация Big-0.

Критерии эффективности

Алгоритм, в конечном счете, выполняется в машинной системе со специфическим набором команд и периферийными устройствами. Для отдельной системы какой-либо алгоритм может быть разработан для полного использования преимуществ данного компьютера и поэтому достигает высокой степени эффективности. Критерий, называемый системной эффективностью (system efficiency), сравнивает скорость выполнения двух или более алгоритмов, которые разработаны для выполнения одной и той же задачи. Выполняя эти алгоритмы на одном компьютере с одними и теми же наборами данных, можно определить относительное время, используя внутренние системные часы. Оценка времени становится мерой системной эффективности для каждого из алгоритмов.

При работе с некоторыми алгоритмами могут стать проблемой ограничения памяти. Процесс может потребовать большого временного хранения, ограничивающего размер первоначального набора данных, или вызвать требующую времени дисковую подкачку. Эффективность пространства (space efficiency) – это мера относительного количества внутренней памяти, используемой каким-либо алгоритмом. Она может указать, какого типа компьютер способен выполнять этот алгоритм и полную системную эффективность алгоритма. Вследствие увеличения объема памяти в новых системах, анализ пространственной эффективности становится менее важным.

Третий критерий эффективности рассматривает внутреннюю структуру алгоритма, анализируя его разработку, включая количество тестов сравнения, итераций и операторов присваивания, используемых алгоритмом. Эти типы измерений являются независимыми от какой-либо отдельной машинной системы. Критерий измеряет вычислительную сложность алгоритма относительно n, количества элементов данных в коллекции. Мы называем эти критерии вычислительной эффективностью (computational efficiency) алгоритма и разрабатываем нотацию Big-0 для построения измерений, являющихся функциями п.

Нотация Big-0. Интуитивно вычислительная эффективность алгоритма измеряется количеством обрабатываемых им данных для определения ключевых операций алгоритма. Эти операции могут зависеть от типа коллекции данных, количества данных и их начального упорядочения.

Н

ахождение минимального элемента в массиве – это простой алгоритм, основная операция которого включает сравнение элементов данных. Для массива с n элементами алгоритм требует n–1 сравнений и мера эффективности пропорциональна n. Другие алгоритмы являются более сложными. Для обменной сортировки обработка данных включает серию сравнений в каждом прохождении. Если А – это массив из n элементов, то обменная сортировка выполняет n–1 проходов. На рис. 4.5 показан этот алгоритм.

Проход 1: Сравнение n–1 – элементов А[1] ... A[n – 1] с А[0] и, если необходимо, такой обмен элементов, чтобы А[0] всегда имел наименьшее значение.

Проход 2: Сравнение п–2 – элементов А[2] ... A[n – 1] с А[1].

Проход i: Для общего случая, сравнение n–i – элементов A[i] ... А[n – i] с A[i – 1].

Общее число сравнений в сортировке обмена задается арифметическим рядом f(n) от 1 до n–1:

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

Количество сравнений зависит от n2.

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

Алгоритмы зависят также от начального упорядочения данных. Например, нахождение минимального значения в массиве значительно упрощается, если известно, что эти данные упорядочены. В возрастающем списке минимальное значение занимает первую позицию. Это значение находится в конце убывающего списка. В этих случаях вычислительная сложность включает единственный доступ к данным, который может быть выполнен в постоянную единицу времени. В примере с сортировкой, если список упорядочен, не требуется никакого обмена. Это условие наилучшего случая, и оно представляет наиболее эффективное выполнение алгоритма. Однако, если список отсортирован в обратном порядке, каждое сравнение приводит к обмену. Это условие наихудшего случая для сортировки. Общий случай предполагает некоторое промежуточное количество обменов в зависимости от порядка данных в списке. Для алгоритмов поиска и сортировки в классе коллекций используются количество сравнений как доминантное действие и меру вычислительной эффективности. Анализ определяет также начальное упорядочение данных, в котором можно различать наилучший случай (best case), наихудший случай (worst case) и средний случай (average case) для алгоритма. Средний случай – это ожидаемая эффективность алгоритма, если он выполняется много раз со случайным набором значений данных.

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

Определяется простая функция g(n) и константу К так, что K*g(n) превышает f(n) по мере того, как п значительно возрастает. Для большого значения п поведение f(n) ограничивается произведением функции g(n) на некоторую константу. Эта математическая концепция, называемая нотацией Big-0, используется, чтобы дать меру вычислительной эффективности.

Определение: Функция f(n) имеет порядок O(g(n)), если имеется константа К и счетчик n0 такие, что f(n)K*g(n), для nn0.

Интуитивно это означает, что функция g в конечном счете превышает значение функции f. Мы говорим, что вычислительная сложность (computational complexity) (или порядок) алгоритма равна O(g(n)).

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

При выполнении Big-0-аппроксимации функции f(n) используется термин доминирование для определения вычислительной сложности. Небольшой опыт работы с неравенствами дает возможность математически проверить эту стратегию. Например, в случае функции

f(n) = n + 2

терм n является доминирующим. Функция g(n) = n используется в следующем неравенстве для проверки того, что f имеет порядок 0(n).

f(n) = n+2 n+n = 2*n для n 2

f также имеет порядок 0(n2) или 0(n3), так как g(n) = n2 и g(n) = n3 ограничивают f(n). Мы выбираем 0(n), что представляет наилучшую оценку для этой функции.

Пример 4.1

1. f(n) = n2 + n + 16. Доминирующий терм – n2, a f имеет порядок 0(n2).

f(n) = n2 + n + 1 n2 + n2 + n2 Зn2 для n1

2. f(n) = sqrt(n+3). Доминирующий терм – sqrt(n), a f имеет порядок О(sqrt(n))

f(n) = sqrt(n+3) sqrt(n+n) = sqrt(2n) = sqrt(2)*sqrt(n) для n 3

3. f(n) = 2n + n + 2. Доминирующий терм – 2n, a f имеет порядок O(2n).

f(n) = 2n + n + 2 2n + 2n +2n = 3*2n, для n 2

Сложность алгоритма. Big-0-оценка дает меру времени выполнения (runtime) алгоритма. Обычно алгоритм имеет разную вычислительную эффективность для наилучшего и наихудшего случаев, поэтому мы вычисляем конкретное значение Big-0 для каждого случая. В разделе 4.4 излагается метод нахождения времени выполнения для последовательного и бинарного поиска. Каждый алгоритм имеет порядок для наилучшего и наихудшего случая, которые различны. Наилучший случай для алгоритма часто не важен, так как эти обстоятельства являются исключительными и неподходящими для решения о выборе какого-либо алгоритма. Наихудший случай может быть важен, так как эти обстоятельства будут наиболее негативно влиять на ваше приложение. Клиент может не допускать наихудшего случая и может предпочесть, чтобы вы выбрали алгоритм, который имеет более узкий диапазон эффективности. В общем, довольно трудно математически определить среднюю эффективность какого-либо алгоритма. Мы будем использовать только очень простые измерения ожидаемых значений и оставим математические детали для курса по теории сложности.

Общий порядок величин

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

Е

сли алгоритм – порядка 0(1), то этот порядок не зависит от количества элементов данных в коллекции. Этот алгоритм выполняется за постоянную единицу времени (constant time). Например, присваивание некоторого значения элементу списка массива имеет порядок 0(1), при условии, что вы храните индекс, который определяет конец списка. Сохранение этого элемента включает только простой оператор присваивания.

А

лгоритм 0(п) является линейным (linear). Сложность этого алгоритма пропорциональна размеру списка. Например, вставка элемента в Конец списка п элементов будет линейной, если мы не храним ссылку на конец списка. Подразумевая, что мы можем просматривать элемент за элементом, алгоритм требует, чтобы мы протестировали n элементов перед определением конца списка. Порядком этого процесса является 0(п). Нахождение максимального элемента в массиве из n элементов – это O(n), потому что должен быть проверен каждый из n элементов.

Ряд алгоритмов имеют порядок, включающий log2n, и называются логарифмическими (logarithmic). Эта сложность возникает, когда алгоритм неоднократно подразделяет данные на подсписки, длиной 1/2, 1/4, 1/8, и так далее от оригинального размера списка. Логарифмические порядки возникают при работе с бинарными деревьями. Бинарный поиск, изложенный в разделе 4.4, имеет сложность среднего и наихудшего случаев 0(log2n).

Алгоритмы, имеющие порядок O(п2), являются квадратическими (quadratic). Наиболее простые алгоритмы сортировки такие, как обменная сортировка, имеют порядок O(п2). Квадратические алгоритмы используются на практике только для относительно небольших значений n. Всякий раз, когда n удваивается, время выполнения такого алгоритма увеличивается на множитель 4. Алгоритм показывает кубическое (cubic) время, если его порядок равен O(n3), и такие алгоритмы очень медленные. Всякий раз, когда n удваивается, Время выполнения алгоритма увеличивается в восемь раз. Алгоритм Уоршела, применимый к графам, – это алгоритм порядка 0(n3).

Алгоритм со сложностью 0(2n) имеет экспоненциальную сложность (exponential complexity). Такие алгоритмы выполняются настолько медленно, что они используются только при малых значениях n. Этот тип сложности часто ассоциируется с проблемами, требующими неоднократного поиска дерева решений.

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

Таблица 4.1