Определение сложности рекурсивных функций (нотация Big O)
У меня завтра экзамен по информатике, и мне нужна помощь в определении сложности этих рекурсивных функций. Я знаю, как решать простые дела, но я все еще пытаюсь узнать, как решать эти более сложные дела. Это были лишь некоторые из примеров проблем, которые я не мог понять. Любая помощь будет очень признательна и очень поможет в моих исследованиях, спасибо!
int recursiveFun1(int n)
{
if (n <= 0)
return 1;
else
return 1 + recursiveFun1(n-1);
}
int recursiveFun2(int n)
{
if (n <= 0)
return 1;
else
return 1 + recursiveFun2(n-5);
}
int recursiveFun3(int n)
{
if (n <= 0)
return 1;
else
return 1 + recursiveFun3(n/5);
}
void recursiveFun4(int n, int m, int o)
{
if (n <= 0)
{
printf("%d, %dn",m, o);
}
else
{
recursiveFun4(n-1, m+1, o);
recursiveFun4(n-1, m, o+1);
}
}
int recursiveFun5(int n)
{
for (i = 0; i < n; i += 2) {
// do something
}
if (n <= 0)
return 1;
else
return 1 + recursiveFun5(n-5);
}
3 ответов
сложность времени в большой o-нотации для каждой функции находится в числовом порядке:
- первая функция вызывается рекурсивно n раз до достижения базового случая, поэтому ее
O(n)
, часто называют линейный. - вторая функция называется n-5 для каждого времени, поэтому мы вычитаем пять из n перед вызовом функции, но n-5 также
O(n)
. (На самом деле называется Порядком n/5 раз. И, O(n/5) = O (n) ). - эта функция log (n) база 5, за каждый раз делим на 5
перед вызовом функции, поэтому его
O(log(n))
(база 5), часто называемая логарифмические и чаще всего Big O notation и анализ сложности использует базу 2. - в-четвертых, это
O(2^n)
или экспоненциальный, так как каждый вызов функции вызывает себя дважды, если он не был рекурсирован n
для случая, когда n <= 0
, T(n) = O(1)
. Поэтому сложность времени будет зависеть от того, когда n >= 0
.
рассмотрим случай n >= 0
в части ниже.
1.
T(n) = a + T(n - 1)
где A-некоторая константа.
по индукции:
T(n) = n * a + T(0) = n * a + b = O(n)
где a, b-некоторая константа.
2.
T(n) = a + T(n - 5)
где A-некоторая константа
By индукция:
T(n) = ceil(n / 5) * a + T(k) = ceil(n / 5) * a + b = O(n)
где a, b-некоторая константа и k
3.
T(n) = a + T(n / 5)
где A-некоторая константа
по индукции:
T(n) = a * log5(n) + T(0) = a * log5(n) + b = O(log n)
где a, b-некоторая константа
4.
T(n) = a + 2 * T(n - 1)
где A-некоторая константа
по индукции:
T(n) = a + 2a + 4a + ... + 2^n * a + T(0) * 2 ^ n
= a * 2^(n+1) - a + b * 2 ^ n
= (2 * a + b) * 2 ^ n - a
= O(2 ^ n)
где a, b-некоторая константа.
5.
T(n) = n / 2 + T(n - 5)
мы можем доказать индукцией, что T(5k) >= T(5k - d)
где d = 0, 1, 2, 3, 4
написать n = 5m - b
(m, b-целое число; b = 0, 1, 2, 3, 4), тогда m = (n + b) / 5
:
T(n) = T(5m - b) <= T(5m)
(на самом деле, чтобы быть более строгим здесь, новую функцию T'(n)
следует определить так, что T'(5r - q) = T(5r)
здесь q = 0, 1, 2, 3, 4
. Мы знаем!--21--> как доказано выше. Когда мы знаем, что T'(n)
находится в O(f)
, что означает, что существует постоянная a, b так что T'(n) <= a * f(n) + b
мы можем сделать вывод, что T(n) <= a * f(n) + b
и поэтому T(n)
находится в O(f)
. Этот шаг не совсем необходимо, но легче думать, когда не приходится иметь дело с остальным.)
расширения T(5m)
:
T(5m) = 5m / 2 + T(5m - 5)
= (5m / 2 + 5 / 2) * m / 2 + T(0)
= O(m ^ 2) = O(n ^ 2)
таким образом, T(n)
is O(n ^ 2)
.
одним из лучших способов аппроксимации сложности рекурсивного алгоритма является рисование дерева рекурсии. После того, как у вас есть рекурсивное дерево:
Complexity = length of tree from root node to leaf node * number of leaf nodes
- первая функция будет иметь длину
n
и номер конечного узла1
Так что сложность будетn*1 = n
вторая функция будет иметь длину
n/5
и количество листовых узлов снова1
Так что сложность будетn/5 * 1 = n/5
. Он должен быть приближен кn
для третьей функции, так как
n
делится на 5 при каждом рекурсивном вызове, длина рекурсивного дерева будетlog(n)(base 5)
, а количество листовых узлов опять 1 так что сложность будетlog(n)(base 5) * 1 = log(n)(base 5)
для четвертой функции, поскольку каждый узел будет иметь два дочерних узла, количество листовых узлов будет равно
(2^n)
и длина рекурсивного дерева будетn
таким образом, сложность будет(2^n) * n
. Но сn
ничтожно перед(2^n)
, его можно игнорировать, а сложность можно только сказать, что(2^n)
.для пятой функции, есть два элемента представляя сложности. Сложность, введенная рекурсивной природой функции, и сложность, введенная
for
петли в каждой функции. При выполнении вышеуказанного вычисления сложность, введенная рекурсивным характером функции, будет~ n
и сложность из-за for loopn
. Общая сложность будетn*n
.
Примечание: это быстрый и грязный способ расчета сложности(ничего официального!). Хотел бы услышать отзывы об этом. Спасибо.