Как использовать Master theorem для описания рекурсии?

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

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

Итак, несколько вопросов: Допустим, вам дано это повторение:

r(n) = 2*r(n-2) + r (n-1);
r (1) = r (2) = 1

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

теперь предположим, что вас попросили найти повторение, T (n), для количества добавлений, выполняемых программа создана из предыдущего повторения. Я вижу, что базовый случай, вероятно, будет T(1) = T(2) = 0, но я не уверен, куда идти оттуда.

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

EDIT: хорошо, я просмотрел некоторые из моих прошлых заданий, чтобы найти другой пример того, где меня спрашивают, "чтобы найти повторение", что является частью этого вопроса, с которым у меня проблемы с post.

повторение, которое описывает в лучшем способ количество операций сложения в следующем фрагменте программы (при вызове с l == 1 и r == n)

int example(A, int l, int r) {
  if (l == r)
    return 2;
  return (A[l] + example(A, l+1, r);
}

5 ответов


несколько лет назад Мохамад АКРА и Луай Баззи доказали результат, который обобщает основной метод-он почти всегда лучше. Вы действительно не должны больше использовать главную теорему...

см., например, эту запись:http://courses.csail.mit.edu/6.046/spring04/handouts/akrabazzi.pdf

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


Закари:

Допустим, вам дано это повторение:

r (n) = 2*r (n-2) + r (n-1); r (1) = r (2) = 1

это, на самом деле, в форме главная теорема? Если так, на словах, что оно говорит?

я думаю, что ваше рекуррентное отношение говорит о том, что для функции " r "с" n " в качестве ее параметра (представляющего общее количество наборов данных, которые вы вводите), что бы вы ни получили на N-я позиция набора данных является выходом n-1-й позиции плюс дважды независимо от результата n-2-й позиции, без выполнения нерекурсивной работы. Когда вы пытаетесь решить рекуррентное отношение, вы пытаетесь выразить его таким образом, чтобы не включать рекурсию.

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

вот форма, которую они дают:

r(n) = a*r(n-1) + b*r(n-2) + f(n)

для "a" и " b " - некоторые константы, а f(n) - некоторая функция от n. В вашем утверждении a = 1, b = 2 и f(n) = 0. Всякий раз, когда f(n) равно нулю, рекуррентное отношение известно как "однородное". Итак, ваше выражение лица однородно.

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

я, что путь к решению однородного рекуррентного отношения состоит в том, чтобы пройти 5 шагов:

1) сформировать характеристическое уравнение, которое имеет вид:

x^k - c[1]*x^k-1 - c[2]*x^k-2 - ... - c[k-1]*x - c[k] = 0

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

x^2 - a*x - b = 0

это потому, что рекуррентное соотношение в виде

r(n) = a*r(n-1) + b*r(n-2)

можно переписать как

r(n) - a*r(n-1) - b*r(n-2) = 0

2) После того, как ваше рекуррентное отношение будет переписано как характеристическое уравнение, затем найдите корни (x[1] и x[2]) характеристического уравнения.

3) с вашими корнями ваше решение теперь будет одной из двух форм:

if x[1]!=x[2]
    c[1]*x[1]^n + c[2]*x[2]^n
else
    c[1]*x[1]^n + n*c[2]*x[2]^n

для Когда n>2. 4) с новой формой вашего рекурсивного решения вы используете начальные условия (r(1) и r (2)) найти c[1] и c[2]

идя с вашим примером вот что мы получаем:

1) r (n) = 1*r (n-1) + 2 * r(n-2) => x^2-x-2 = 0

2) решения для x

x = (-1 +- sqrt(-1^2 - 4(1)(-2)))/2(1)

    x[1] = ((-1 + 3)/2) = 1
    x[2] = ((-1 - 3)/2) = -2

3) С x[1]!= x[2], ваше решение имеет вид:

c[1](x[1])^n + c[2](x[2])^n

4) Теперь, используя начальные условия, чтобы найти две константы c[1] и C[2]:

c[1](1)^1 + c[2](-2)^1 = 1
c[1](1)^2 + c[2](-2)^2 = 1
[ 1 1   | 1 ]
[ 1 2   | 1 ] 

Закари:

повторение, которое описывает в лучшем способ количество операций сложения в следующем фрагменте программы (при вызове с l == 1 и r == n)

int example(A, int l, int r) {
  if (l == r)
    return 2;
  return (A[l] + example(A, l+1, r);
}

вот значения сложности времени для вашего данного кода, когда r>l:

int example(A, int l, int r) {      =>  T(r) = 0
  if (l == r)               =>  T(r) = 1
    return 2;               =>  T(r) = 1
  return (A[l] + example(A, l+1, r);    =>  T(r) = 1 + T(r-(l+1))
}

Total:                      T(r) = 3 + T(r-(l+1))

Else, когда r==l, то T (r) = 2, потому что оператор if и возврат требуют 1 шага за исполнение.


ваш метод, написанный в коде с использованием рекурсивной функции, будет выглядеть так:

function r(int n) 
{
  if (n == 2) return 1;
  if (n == 1) return 1;
  return 2 * r(n-2) + r(n-1);  // I guess we're assuming n > 2
}

Я не уверен, что такое "повторение", но рекурсивная функция-это просто та, которая называет себя.

рекурсивные функции нужен escape clause (некоторый нерекурсивный случай-например, "если n==1 возвращает 1"), чтобы предотвратить Переполнение Стека error (т. е. функция вызывается так много, что у интерпретатора заканчивается память или другое ресурсы)


простая программа, которая будет реализовывать это будет выглядеть так:

public int r(int input) {
    if (input == 1 || input == 2) {
        return 1;
    } else {
        return 2 * r(input - 2) + r(input -1)
    }
}

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


"Я точно не знаю, что такое "повторение""

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

и цель их решения, я думаю, состоит в том, чтобы перейти от рекурсивного определения к тому, что нет. Скажем, если бы у Вас было T(0) = 2 и T(n) = 2 + T(n-1) для всех n>0, вам пришлось бы перейти от выражения "T(n) = 2 + T (n-1)" к одному, как "2n+2".

источники: 1) "Дискретная математика с теорией графов-второе издание", Эдгар г. Гудаир и Майкл М. Парментер 2) "компьютерные алгоритмы на C++", автор Эллис Горовиц, С. Сахны, и Sanguthevar Rajasekaran.