Рекуррентное соотношение для алгоритма - PullRequest
0 голосов
/ 24 сентября 2018

Я уже дал следующий алгоритм, который я должен найти отношение повторения.

int Recursive(int n)
{
   if(n<=1)
     return n;
   sum=0;
   for(int j=0;j<n;j++)
      sum++;
   return Recursive(n/2) + Recursive(n/2) + sum;
}

Я получил отношение повторения для вышеупомянутого алгоритма как

T(n) = 2 T(n/2) + constant

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

Может кто-нибудь помочь мне получить правильное отношение повторения?Спасибо.

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Предположения, сделанные в этом ответе:

  • sum объявлено глобально - поскольку явно отсутствующее объявление, как вы заявили, не является опечаткой.
  • Вопрос требуетвозвращаемое значение, а не сложность по времени.
  • Выражения в выражении возврата оцениваются в порядке их появления;это не гарантируется стандартом C, поэтому ответ технически не определен.

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

  • Возвращает свой аргумент (if n <= 1)
  • Сбрасывает значение sum в 0

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

Два отдельных вызова на Recursive(n / 2) могут быть объединены в один вызов, не влияя на возвращаемое значение: return 2 * Recursive(n / 2) + sum;.

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


Теперь для ключевой части.Вызов Recursive(n / 2) перезаписывает значение sum перед возвратом функции, отменяя работу, выполненную предыдущим циклом for.Это перезаписывающее поведение продолжается по иерархии рекурсии, до последнего вызова, когда выполняется условие остановки n <= 1 (вместо этого возвращается просто n).Из этого следует, что:

Существует только одно значение sum, которое вносит вклад в окончательное возвращаемое значение, определяемое его значением после предпоследнего вызовадо Recursive.


Из-за усечения целочисленным делением, когда выполняется предпоследний вызов n равен всегда 2 или 3 (оба из которых удовлетворяют n / 2 = 1);таким образом, это также возможные окончательные значения sum.

Какие значения n дают sum = 2 и sum = 3 соответственно?Иллюстративно рассмотреть двоичное представление n.

Целочисленное деление на 2 эквивалентно сдвигу битового набора «вправо» на 1 (или «влево» в зависимости от порядкового номера ...) и отбрасыванию младшего значащего бита.Из этого следует, что окончательное значение sum зависит только от 2 старших значащих битов n:

 initial bit-pattern  >>  penultimate call
 -----------------------------------------
 ...000 10 xxx...         ...0000 10 = 2       
 ...000 11 xxx...         ...0000 11 = 3

 xxx: discarded bits

Битовая последовательность n имеет floor(log2(n)) + 1значимые биты;итоговое значение sum может поэтому быть кратко выражено как:

S(n) = 2 + second_most_significant_bit(n)

Сколько раз sum добавляется к возвращаемому значению?Число рекурсивных звонков на Recursive (т. Е. Общее количество звонков минус один, включая начальный звонок, но исключая последний).Это задается как floor(log2(n)):

enter image description here

Обратите внимание, что возвращаемое значение последнего вызова будет всегда быть 1если изначально n >= 1.Поэтому окончательное возвращаемое значение Recursive определяется следующим образом:

enter image description here


Проверка кода C для подтверждения:

// override the library definition of log2 to use integers only
int log2(int n) {
   int b = 0;
   while ((n >>= 1) != 0)
      b++;
   return b;
}

// get i-th bit from bit pattern of n
int get_bit(int n, int i) {
   return (n >> (i - 1)) & 1;
}

// calculating return value of Recursive using equation above
int Value(int n) {
   int l2n = log2(n);    // floor(log2(n))
   int p2l = 1 << l2n;   // 2^(floor(log2(n)))
   return p2l + (p2l - 1) * (2 + get_bit(n, l2n));
}

Результаты:

n        | Recursive    Value
-------------------------------
2        |  4           4
3        |  5           5
4 - 5    |  10          10
6 - 7    |  13          13
8 - 11   |  22          22
12 - 15  |  29          29
16 - 23  |  46          46
24 - 31  |  61          61
32 - 47  |  94          94
48 - 63  |  125         125
64 - 95  |  190         190
0 голосов
/ 24 сентября 2018

Я не уверен насчет постоянной части этого рекуррентного отношения

Не существует постоянной части , поскольку sum равно n после цикла,Это дает:

T(n) = 2T(n/2)+n

Таким образом, если сумма является глобальной переменной, T(n) = 2T(n/2)+C(Constant) и если сумма является локальной переменной T(n) = 2T(n/2)+n.Правильно ли я?

Нет, как написал mch:

Кажется, что сумма является глобальной переменной ... В этом случае было бы неопределенным, если sum или одиниз Recursive(n/2) будет оцениваться первым.

Это означает, что это будет неопределено , T(n) = 2T(n/2)+n или T(n) = 2T(n/2)+n/2;ни в том, ни в другом случае нет постоянной части.

...