Опубликован: 05.01.2015 | Доступ: свободный | Студентов: 2023 / 0 | Длительность: 63:16:00
Лекция 2:

Принципы анализа алгоритмов

Простейшие рекурсии

Как мы увидим далее в этой книге, многие алгоритмы основаны на принципе рекурсивного разбиения большой задачи на меньшие, а решения подзадач используются для решения исходной задачи. Эта тема подробно обсуждается в "Рекурсия и деревья" , в основном с практической точки зрения, где основное внимание уделено различным реализациям и приложениям. Кроме того, в разделе 2.6 приводится подробный пример. А в этом разделе будут рассмотрены простейшие методы анализа таких алгоритмов и вывод решений нескольких стандартных формул, которые возникают при анализе многих изучаемых алгоритмов. Понимание математических свойств формул в этом разделе дает необходимое понимание свойств производительности алгоритмов.

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

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


            C_N = C_N-1 + N
          , где $N\geq2$ и 
            C_1 = 1
          .

Решение: C_N имеет порядок 
            N^2/ 2
          . Для решения рекуррентного уравнения его можно развернуть, применяя само к себе следующим образом:


            \begin{equation*}
         
            C_{N}&=C_{N-1}+N\\
            &=C_{N-2}+(N-1)+N\\
            &=C_{N-3}+(N-2)+(N-1)+N\\
            \vdots
    
            \end{equation*}
Продолжая таким же образом, можно получить

            \begin{equation*}
           
            C_{N}&=C_{1}+2+\ldots+(N-2)+(N-1)+N\\
            &=1+2+\ldots+(N-2)+(N-1)+N\\
            &=\dfrac{N(N+1)}{2}
      
            \end{equation*}

Подсчет суммы 1 + 2 + ... + (N - 2) + (N - 1) + N элементарен: прибавим к сумме ее же, но в обратном порядке. Результирующая сумма - удвоенный искомый результат - будет состоять из N слагаемых, каждое из которых равно N + 1.

Формула 2.2. В рекурсивной программе, где на каждом шаге количество вводов уменьшается вдвое, возникает следующее рекуррентное соотношение: $$C_{N}=C_{N/2}+1{, где }N\geq2{ и }C_{1}=1$$

Решение: CN имеет порядок lg N. Это уравнение бессмысленно, если N нечетно, или же нужно предположить, что  N/2 - целочисленное деление. Чтобы рекурсия была всегда определена, предположим, что 
            N= 2^n
          . (Отсюда п =  lg N.) Тогда развернуть рекурсию еще проще, чем в предыдущем случае:


            \begin{equation*}
C_{2^{n}}&=C_{2^{n-1}}+1\\
            &=C_{2^{n-2}}+1+1\\
            &=C_{2^{n-3}}+3\\
            \vdots\\
            &=C_{2^{n}}+n\\
            &=n+1.
 \end{equation*}

Точное решение для произвольного N зависит от интерпретации  N/2. Если  N/2 представляет собой $\lfloor N/2\rfloor$, то существует очень простое решение: CN - это количество битов в двоичном представлении числа N, т.е. по определению $\lfloor lgN\rfloor+1$. Этот вывод немедленно следует из того, что операция отбрасывания правого бита в двоичном представлении любого числа N > 0 превращает его в $\lfloor N/2\rfloor$ (см. рис. 2.6).

 Целочисленные функции и двоичные представления

Рис. 2.6. Целочисленные функции и двоичные представления

Для заданного двоичного представления числа N (в центре) отбрасывание правого бита дает $\lfloor N/2\rfloor$. То есть количество битов в двоичном представлении числа N на единицу больше, чем в представлении числа $\lfloor N/2\rfloor$. Поэтому количество битов в двоичном представлении числа - $N\lfloor N/2\rfloor+1$ - является решением формулы 2.2 в случае интерпретации N/2 как $\lfloor N/2\rfloor$.

Формула 2.3. В рекурсивной программе, где объем входных данных уменьшается вдвое, но необходимо проверить каждый элемент, возникает следующее рекуррентное соотношение: $$C_{N}=C_{N/2}+N{, где }N\geq2{ и }C_{1}=0$$.

Решение: CN имеет порядок 2N. Рекурсия развертывается в сумму:

N + N/2 + N/4 + N/8 + ... .

(Как и формуле 2.2, рекуррентное соотношение определено точно только в том случае, если N является степенью числа 2). Для бесконечной последовательности сумма простой геометрической прогрессии равна в точности 2N. Однако поскольку используется целочисленное деление, и мы останавливаемся на 1, это значение является приближением к точному ответу. В точном решении используются свойства двоичного представления числа N.

Формула 2.4. В рекурсивной программе, которая должна выполнить линейный проход по входным данным до, в течение или после разбиения их на две половины, возникает следующее рекуррентное соотношение: $$C_{N}=2C_{N/2}+N{, где }N\geq2{ и }C_{1}=0$$.

Решение: CN имеет порядок NlgN. Это решение применяется намного чаще, чем остальные из приведенных здесь, поскольку эта рекурсия используется в целом семействе алгоритмов "разделяй и властвуй".


            \begin{equation*}
C_{2^{n}}&=2C_{2^{n-1}}+2^{n}\\
            \dfrac{C_{2^{n}}}{2^{n}}&=\dfrac{C_{2^{n-1}}}{2^{n-1}}+1\\
            &=\dfrac{C_{2^{n-2}}}{2^{n-2}}+1+1\\
            \vdots\\
            &=n.
            \end{equation*}

Решение находится почти так же, как это было сделано в формуле 2.2, но с дополнительным приемом на втором шаге - делением обеих частей равенства на 2^n, который позволяет развернуть рекурсию.

Формула 2.5. В рекурсивной программе, которая разбивает входные данные пополам, а затем выполняет постоянное количество других операций (см. "Рекурсия и деревья" ) возникает следующая рекурсия. $$C_{N}=2C_{N/2}+1{, где }N\geq2{ и }C_{1}=1$$.

Решение: C_N имеет порядок 2N. Это решение можно получить так же, как и решение формулы 2.4.

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

Упражнения

  • 2.33. Составьте таблицу значений C_N, заданных формулой 2.2 для $1\leq N\leq32$, считая, что  N/2 означает $\lfloor N/2\rfloor$.
  • 2.34. Выполните упражнение 2.33, но считая, что  N/2 означает $\lceil N/2\rceil$.
  • 2.35. Выполните упражнение 2.34 для формулы 2.3.
  • 2.36. Предположим, что f_N пропорционально постоянной величине и что $C_{N}=C_{N/2}+f_{N}{ при }N\geq t{ и }0\leq C_{N}<c{ при }N<t$, где с и t - постоянные. Покажите, что C_N пропорционально lgN.
  • 2.37. Сформулируйте и докажите обобщенные версии формул 2.3 - 2.5, аналогичные обобщенной версии формулы 2.2 в упражнении 2.36.
  • 2.38. Составьте таблицу значений C_N, заданных формулой 2.4 при $1\leq N\leq32$ для трех следующих случаев: (1)  N/2 означает $\lfloor N/2\rfloor$, (2)  N/2 означает $\lceil N/2\rceil$, (3) 2C_N/2 равно $C_{\lfloor N/2\rfloor}+C_{\lceil N/2\rceil}$
  • 2.39. Решите уравнение 2.4 для случая, когда  N/2 означает $\lfloor N/2\rfloor$, используя соответствие двоичному представлению числа N, как это было сделано в доказательстве формулы 2.2. Подсказка: Рассмотрите все числа, меньшие N.
  • 2.40. Решите рекуррентное уравнение $C_{N}=C_{N/2}+N^{2}$ при $N\geq 2{\ и\ }C_{1}=0$, если N является степенью числа 2.
  • 2.41. Решите рекуррентное уравнение $C_{N}=C_{N/\alpha}+1$ при $N\geq 2{\ и\ }C_{1}=0$, если N является степенью числа а.
  • 2.42. Решите рекуррентное уравнение $C_{N}=\alpha C_{N/2}+N^{2}$ при $N\geq 2{\ и\ }C_{1}=1$, если N является степенью числа 2.
  • 2.43. Решите рекуррентное уравнение $C_{N}=(C_{N/2})^{2}+N^{2}$ при $N\geq 2{\ и\ }C_{1}=1$, если N является степенью числа 2.
  • 2.44. Решите рекуррентное уравнение $C_{N}=\left(2+\dfrac{1}{\lg{N}}\right)C_{N/2}$ при $N\geq 2{\ и\ }C_{1}=1$, если N является степенью числа 2.
  • 2.45. Рассмотрите семейство рекурсий наподобие формулы 2.1, где  N/2 может означать $\lfloor N/2\rfloor$ или $\lceil N/2\rceil$, с единственным требованием: рекурсия выполняется при 
          N > с_0
        , а при $N\leq c_{0}$ имеет место 
          C_N = O(1)
        . Докажите, что решением всех таких рекурсий является формула lgN + O(1).
  • 2.46. Выведите обобщенные рекурсии и их решения, как в упражнении 2.45, для формул 2.2-2.5.
Никита Андриянов
Никита Андриянов
Дмитрий Уколов
Дмитрий Уколов
Семен Дядькин
Семен Дядькин
Беларусь, Минск, БГУ, 2003