RSS    

   Реферат: VB, MS Access, VC++, Delphi, Builder C++ принципы(технология), алгоритмы программирования

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

Что такое алгоритмы?

Алгоритм – это последовательность инструкций для выполнения какого‑либо задания. Когда вы даете кому‑то инструкции о том, как отремонтировать газонокосилку, испечь торт, вы тем самым задаете алгоритм действий. Конечно, подобные бытовые алгоритмы описываются неформально, например, так:

Проверьте, находится ли машина на стоянке.

Убедитесь, что машина поставлена на ручной тормоз.

Поверните ключ.

И т.д.

==========1

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

Если же составляется алгоритм для исполнения компьютером, вы не можете полагаться на то, что компьютер поймет что‑либо, если это не описано заранее. Словарь компьютера (язык программирования) очень ограничен и все инструкции для компьютера должны быть сформулированы на этом языке. Поэтому для написания компьютерных алгоритмов используется формализованный стиль.

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

Если дверь закрыта:

    Вставить ключ в замок

    Повернуть ключ

    Если дверь остается закрытой, то:

        Повернуть ключ в другую сторону

Повернуть ручку двери

И т.д.

Этот фрагмент «кода» отвечает только за открывание двери; при этом даже не проверяется, какая дверь открывается. Если дверь заело или в машине установлена противоугонная система, то алгоритм открывания двери может быть достаточно сложным.

Формализацией алгоритмов занимаются уже тысячи лет. За 300 лет до н.э. Евклид написал алгоритмы деления углов пополам, проверки равенства треугольников и решения других геометрических задач. Он начал с небольшого словаря аксиом, таких как «параллельные линии не пересекаются» и построил на их основе алгоритмы для решения сложных задач.

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

Анализ скорости выполнения алгоритмов

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

Пространство — время [RP1] 

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

быстрее, используя больше памяти, или наоборот, медленнее, заняв меньший объем памяти.

===========2

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

При этом мы получим результат практически мгновенно, но это потребует большого объема памяти. Карта улиц для большого города, такого как Бостон или Денвер, может содержать сотни тысяч точек. Для такой сети таблица кратчайших расстояний содержала бы более 10 миллиардов записей. В этом случае выбор между временем исполнения и объемом требуемой памяти очевиден: поставив дополнительные 10 гигабайт оперативной памяти, можно заставить программу выполняться гораздо быстрее.

Из этой связи вытекает идея пространственно‑временной сложности алгоритмов. При этом подходе сложность алгоритма оценивается в терминах времени и пространства, и находится компромисс между ними.

В этом материале основное внимание уделяется временной сложности, но мы также постарались обратить внимание и на особые требования к объему памяти для некоторых алгоритмов. Например, сортировка слиянием (mergesort), обсуждаемая в 9 главе, требует больше временной памяти. Другие алгоритмы, например пирамидальная сортировка (heapsort), которая также обсуждается в 9 главе, требует обычного объема памяти.

Оценка с точностью до порядка

При сравнении различных алгоритмов важно понимать, как сложность алгоритма соотносится со сложностью решаемой задачи. При расчетах по одному алгоритму сортировка тысячи чисел может занять 1 секунду, а сортировка миллиона — 10 секунд, в то время как расчеты по другому алгоритму могут потребовать 2 и 5 секунд соответственно. В этом случае нельзя однозначно сказать, какая из двух программ лучше — это будет зависеть от исходных данных.

Различие производительности алгоритмов на задачах разной вычислительной сложности часто более важно, чем просто скорость алгоритма. В вышеприведенном случае, первый алгоритм быстрее сортирует короткие списки, а второй — длинные.

Производительность алгоритма можно оценить по порядку величины. Алгоритм имеет сложность порядка O(f(N)) (произносится «О большое от F от N»), если время выполнения алгоритма растет пропорционально функции f(N) с увеличением размерности исходных данных N. Например, рассмотрим фрагмент кода, сортирующий положительные числа:

For I = 1 To N

    'Поиск наибольшего элемента в списке.

    MaxValue = 0

    For J = 1 to N

        If Value(J) > MaxValue Then

           MaxValue = Value(J)

            MaxJ = J

        End If

    Next J

    'Вывод наибольшего элемента на печать.

    Print Format$(MaxJ) & ":" & Str$(MaxValue)

    'Обнуление элемента для исключения его из дальнейшего поиска.

    Value(MaxJ) = 0

Next I

===============3

В этом алгоритме переменная цикла I последовательно принимает значения от 1 до N. Для каждого приращения I переменная J в свою очередь также принимает значения от 1 до N. Таким образом, в каждом внешнем цикле выполняется еще N внутренних циклов. В итоге внутренний цикл выполняется N*N или N2 раз и, следовательно, сложность алгоритма порядка O(N2).

При оценке порядка сложности алгоритмов используется только наиболее быстро растущая часть уравнения алгоритма. Допустим, время выполнения алгоритма пропорционально N3+N. Тогда сложность алгоритма будет равна O(N3). Отбрасывание медленно растущих частей уравнения позволяет оценить поведение алгоритма при увеличении размерности данных задачи N.

При больших N вклад второй части в уравнение N3+N становится все менее заметным. При N=100, разность N3+N=1.000.100 и N3 равна всего 100, или менее чем 0,01 процента. Но это верно только для больших N. При N=2, разность между N3+N =10 и N3=8 равна 2, а это уже 20 процентов.

Постоянные множители в соотношении также игнорируются. Это позволяет легко оценить изменения в вычислительной сложности задачи. Алгоритм, время выполнения которого пропорционально 3*N2, будет иметь порядок O(N2). Если увеличить N в 2 раза, то время выполнения задачи возрастет примерно в 22, то есть в 4 раза.

Игнорирование постоянных множителей позволяет также упростить подсчет числа шагов алгоритма. В предыдущем примере внутренний цикл выполняется N2 раз, при этом внутри цикла выполняется несколько инструкций. Можно просто подсчитать число инструкций If, можно подсчитать также инструкции, выполняемые внутри цикла или, кроме того, еще и инструкции во внешнем цикле, например операторы Print.

Вычислительная сложность алгоритма при этом будет пропорциональна N2, 3*N2 или 3*N2+N. Оценка сложности алгоритма по порядку величины даст одно и то же значение O(N3) и отпадет необходимость в точном подсчете количества операторов.

Поиск сложных частей алгоритма

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

============4

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

Приведем в качестве примера программу, содержащую медленную процедуру Slow со сложностью порядка O(N3) и быструю процедуру Fast со сложностью порядка O(N2). Сложность всей программы будет зависеть от соотношения между этими двумя процедурами.

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82


Новости


Быстрый поиск

Группа вКонтакте: новости

Пока нет

Новости в Twitter и Facebook

                   

Новости

© 2010.