Вычислить сложность вложенного цикла for

Я хочу рассчитать сложность этого вложенного цикла for:

s = 0;
for(i=1; i<=n; i*=2)
   for(j=1; j<=i; j*=2)
      s++;

Какую стратегию я использую, чтобы найти большую сложность этого фрагмента кода?


person Sarah Zeftawy    schedule 15.03.2013    source источник
comment
Попробуйте просмотреть это: stackoverflow.com/questions/8331479/determining-big -o-notation Сомневаюсь, что кто-то просто даст вам ответ.   -  person Seth Moore    schedule 15.03.2013
comment
@smoore: значение i во внутреннем цикле ограничено сверху n.   -  person Fred Foo    schedule 15.03.2013
comment
Да, только что отозвал свой комментарий :-)   -  person Seth Moore    schedule 15.03.2013
comment
@smoore: происходит постоянно. Я не собирался публиковать его, пока не увидел неправильные ответы.   -  person Fred Foo    schedule 15.03.2013


Ответы (4)


Внешний цикл проходит через 1, 2, 4, 8, ... n, что занимает O(lg n) шагов, потому что вы можете удвоить только один O(lg < em>n) раз, пока не нажмете n.

Внутренний цикл делает то же самое. Он достигает только i, но на последней итерации внешнего цикла i достигает своего максимального значения, которое снова равно n, так что это также O(lg n).

В результате получается верхняя граница O((lg n)²), которая обычно обозначается аббревиатурой O(lg² n).

person Fred Foo    schedule 15.03.2013
comment
Многие книги считают, что последнее обозначение означает log log n - person user1952500; 15.03.2013
comment
@ user1952500: я никогда не видел такого использования lg² n, но именно поэтому я дал обе записи (см. Также math.se). - person Fred Foo; 16.03.2013
comment
loglogn означает log(logn), тогда как log^2(n) означает logn*logn - person SomeWittyUsername; 17.03.2013
comment
Хотя результат правильный, анализ является грубым и может легко пропустить самую узкую границу. - person SomeWittyUsername; 18.03.2013

Как получить ответ самостоятельно

Подставьте в уравнение разные значения n и нарисуйте диаграмму, сколько раз выполняется самая внутренняя часть цикла:

s = 0;
for(i=1; i<=n; i*=2)
  for(j=1; j<=i; j*=2)
    s++;

Что-то вроде этого:

n     num_times_inner_loop_part_runs
1     1
2     3
3     3
4     6
5     6
6     6
7     6
8     10
9     10
...
15    10
16    15
...
31    15
32    21

Вы можете получить эти точки данных с помощью такой программы:

int n = 9;  //change this n
int counter = 0;
for(i=1; i<=n; i*=2){
  for(j=1; j<=i; j*=2){
    s++;
    counter++;
  }
}
cout << "counter is: " <<  counter << endl;

Нанесите num_times_inner_loop_part на координатную плоскость X/Y, и вы увидите кривую.

Назовите кривую, которая подходит ближе всего. В данном случае это X = (log(Y)^2)

Если вы нанесете свои данные и X = (log(Y)^2), вы обнаружите, что они должны перекрывать друг друга.

Таким образом, сложность этой функции составляет O((log(n))^2), что является улучшением по сравнению с O(n).

person Eric Leschinski    schedule 15.03.2013
comment
Ваш вывод не соответствует вашим результатам. num_times_inner_loop_part_runs = n(n + 1) / 2. Возможно, у вас было i++ вместо i*=2 - person Eric; 15.03.2013
comment
ох, приращение j * = 2. Я починил это. - person Eric Leschinski; 15.03.2013

Анализ времени этого фрагмента кода:

Анализ

person SomeWittyUsername    schedule 17.03.2013

Временная сложность вашего алгоритма может быть формально представлена ​​следующим образом:

введите здесь описание изображения

Этот документ (последний слайд) может оказаться для вас чрезвычайно полезным .

person Mohamed Ennahdi El Idrissi    schedule 17.03.2014