#c #for-loop #time-complexity
#c #для цикла #временная сложность
Вопрос:
Как найти временную сложность этой функции:
Код
void f(int n)
{
for(int i=0; i<n; i)
for(int j=0; j<i; j)
for(int k=i*j; k>0; k/=2)
printf("~");
}
Я сделал обоснованное предположение (n^2)*log(n)
, основанное на интуиции, и оно оказалось правильным.
Но, похоже, я не могу найти для этого точного объяснения.
Комментарии:
1. Похоже, единственная сложная часть — это то, как справиться с
k=i*j
. С этим можно справиться, осознав, чтоlog(n^2) = 2log(n)
а big-O игнорирует константы.2. Действительно, это правда, я заметил эти вещи, но дело в том, что, как вы сказали, часть i j сбивает с толку. Самый внутренний цикл выполняется log (i j) раз, поэтому здесь у нас есть какая-то сумма, которую я, похоже, не могу точно сформулировать
3. А, я понимаю. Вы ищете точную формулу, например
1 2 3 ... n = n(n 1)/2
. Я не уверен, что для этого кода существует такая формула, но вы можете попытать счастья на math stack exchange .
Ответ №1:
Для каждого значения i
, i>0
будут i-1
значения внутреннего цикла, каждое из которых для k
начинается соответственно с:
i*1, i*2, ..., i(i-1)
Поскольку k
делится на 2
до тех пор, пока не достигнет 0
, каждый из этих циклов «внутри-внутри» требует lg(k)
шагов. Следовательно
lg(i*1) lg(i*2) ... lg(i(i-1)) = lg(i) lg(i) lg(2) ... lg(i) lg(i-1)
= (i-1)lg(i) lg(2) ... lg(i-1)
Следовательно, общее значение будет
f(n) ::= sum_{i=1}^{n-1} i*lg(i) lg(2) ... lg(i-1)
Давайте теперь свяжемся f(n 1)
сверху:
f(n 1) <= sum_{i-1}^n i*lg(i) (i-1)lg(i-1)
<= 2*sum_{i-1}^n i*lg(i)
<= C*integral_0^n x(ln x) ; integral bound, some constant C
= C/2(n^2(ln n) - n^2/2) ; integral x*ln(x) = x^2/2*ln(x) - x^2/4
= O(n^2*lg(n))
Если мы теперь свяжем f(n 1)
снизу:
f(n 1) >= sum_{i=1}^n i*lg(i)
>= C*integral_0^n x(ln x) ; integral bound
= C*(n^2*ln(n)/2 - n^2/4) ; integral x*ln(x) = x^2/2*ln(x) - x^2/4
>= C/4(n^2*ln(n))
= O(n^2*lg(n))