Сложность O(n)
, как показывал @paragon. Кроме того, иногда просто подсчитывая, сколько итераций произойдет, часто выявляется сложность:
#include <iostream>
unsigned f(unsigned n) {
unsigned ctr = 0u;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; j += pow(i, 2)) {
++ctr;
}
}
return ctr;
}
int main() {
for (unsigned n = 1u; n < 9u; ++n) {
unsigned a = std::pow(10, n) * 2;
unsigned b = std::pow(10, n);
std::cout << "f(" << a << ") / f(" << b << ") = " << f(a) / static_cast<double>(f(b)) << '\n';
}
}
показывает, что он явно приближается к сложности O(n)
:
f(20) / f(10) = 2.09091
f(200) / f(100) = 2.04016
f(2000) / f(1000) = 2.01001
f(20000) / f(10000) = 2.0035
f(200000) / f(100000) = 2.00105
f(2000000) / f(1000000) = 2.00032
f(20000000) / f(10000000) = 2.0001
f(200000000) / f(100000000) = 2.00003
А что если я поменяю часть pow на pow (i, 3) или более высокую мощность?
оно останется по-прежнему O(n)
. Это имеет смысл, поскольку чем выше показатель степени, тем больше j
увеличивается, завершая свой цикл еще раньше, уменьшая сложность по сравнению с циклом i
(i <= n
=> O(n)
):
[pow = 1] f(20000000) / f(10000000) = 2.08026
[pow = 2] f(20000000) / f(10000000) = 2.0001
[pow = 3] f(20000000) / f(10000000) = 2.00001
[pow = 4] f(20000000) / f(10000000) = 2
[pow = 5] f(20000000) / f(10000000) = 2
[pow = 6] f(20000000) / f(10000000) = 2
[pow = 7] f(20000000) / f(10000000) = 2
//...
добавление к ответу @ paragon, серия
, где p
- показатель степени. С ростом x
доля сокращается, и сумма приближается к фиксированному значению (за исключением небольших значений p
, я думаю)