Наивная рекурсивная версия Фибоначчи имеет экспоненциальный характер из-за повторения в вычислениях:
В корне вы вычисляете:
F (n) зависит от F (n-1) и F (n-2)
F (n-1) снова зависит от F (n-2) и F (n-3)
F (n-2) снова зависит от F (n-3) и F (n-4)
тогда у вас на каждом уровне 2 рекурсивные вызовы, которые тратят много данных в расчете, функция времени будет выглядеть так:
T (n) = T (n-1) + T (n-2) + C, с постоянной C
T (n-1) = T (n-2) + T (n-3)> T (n-2), затем
T (n)> 2 * T (n-2)
...
T (n)> 2 ^ (n / 2) * T (1) = O (2 ^ (n / 2))
Это просто нижняя граница, которую для целей вашего анализа должно быть достаточно, но функция реального времени является фактором постоянной по той же формуле Фибоначчи, а закрытая форма , как известно, экспоненциальная золотого сечения.
Кроме того, вы можете найти оптимизированные версии Фибоначчи, использующие динамическое программирование, например:
static int fib(int n)
{
/* memory */
int f[] = new int[n+1];
int i;
/* Init */
f[0] = 0;
f[1] = 1;
/* Fill */
for (i = 2; i <= n; i++)
{
f[i] = f[i-1] + f[i-2];
}
return f[n];
}
Это оптимизировано и делает только n шагов, но также экспоненциально.
Функции стоимости определяются от Входного размера до количества шагов для решения проблемы. Когда вы видите динамическую версию Фибоначчи ( n шагов для вычисления таблицы) или самый простой алгоритм, чтобы узнать, является ли число простым ( sqrt (n) для анализа действительных делителей число). Вы можете подумать, что эти алгоритмы: O (n) или O (sqrt (n)) , но это просто неверно по следующей причине:
Входными данными для вашего алгоритма является число: n , используя двоичную запись, размер ввода для целого числа n равен log2 (n) , затем выполняется изменение переменной из
m = log2(n) // your real input size
позвольте узнать количество шагов в зависимости от размера ввода
m = log2(n)
2^m = 2^log2(n) = n
тогда стоимость вашего алгоритма как функция размера ввода равна:
T(m) = n steps = 2^m steps
и поэтому стоимость экспоненциальная.