2015-08-25 3 views
17

Мне нужно проанализировать этот цикл, среди прочих, и определить его время работы с использованием нотации Big-O.Анализ Big-O для цикла

for (int i = 0; i < n; i += 4) 
    for (int j = 0; j < n; j++) 
     for (int k = 1; k < j*j; k *= 2)` 

Вот что я до сих пор:

for (int i = 0; i < n; i += 4) = n 

for (int j = 0; j < n; j++) = n 

for (int k = 1; k < j*j; k *= 2) = log^2 n 

Теперь проблема я иду окончательное время работы цикла. Мое лучшее предположение - O (n^2), однако я не уверен, что это правильно. Может ли кто-нибудь помочь?

Редактировать: извините за О -> O вещь. Мой учебник использует «Big-OH»

+1

Поскольку вы выполняете все внутренние циклы для каждой итерации внешних петель, это будет простое умножение, то есть O (n * n * log (n)). (Однако не проверяйте свои индивидуальные результаты). – Thomas

+2

Я думаю, что третий цикл не является «log^2 n', а скорее« log n^2 », который является« O (log n) ». –

+0

@Thomas, чтобы вы все равно размножались как обычно, хотя есть функция журнала? JuanLopes вы правы! Благодарю. –

ответ

18

Прежде всего обратите внимание, что внешний цикл не зависит от остальных двух - он просто добавляет множитель (n/4)*. Мы рассмотрим это позже.

Теперь давайте рассмотрим сложность

for (int j = 0; j < n; j++) 
    for (int k = 1; k < j*j; k *= 2) 

Мы имеем следующую сумму:

0 + войти (1) + 2 входа (2 * 2) + ... + журнал (п * п)

хорошо отметить, что журнал (п^2) = 2 * .log (n). Таким образом, мы переделан сумма к:

2 * (0 + войти (1) + журнал (2) + ... + журнал (п))

Анализ этой суммы непросто, но посмотрите на this post. Используя приближение Стерлинга, можно предположить, что оно принадлежит O(n*log(n)). Таким образом, общая сложность O((n/4)*2*n*log(n))= O(n^2*log(n))

+0

Это было очень полезно, спасибо. Тем не менее, я не на 100% рассчитываю на внешний цикл. Не могли бы вы немного разобраться? –

+0

@SarahvdByl вы имеете в виду цикл над 'i'? Он не зависит от других циклов, и его выполнение эквивалентно выполнению внутренних циклов 'n/4' раз. –

+4

Нет необходимости в Стирлинге: log2 (1) + log2 (2) + ... + log2 (n) <= log2 (n) + log2 (n) + ... + log2 (n) = n * log2 (n). Это не доказывает, что оценка плотная, но для получения O (-) этого достаточно. – chi

4

Время Сложность цикла рассматривается как О (п), если переменные цикла увеличивается/уменьшается на постоянную величину (что с в примерах ниже):

for (int i = 1; i <= n; i += c) { 
     // some O(1) expressions 
    } 

    for (int i = n; i > 0; i -= c) { 
     // some O(1) expressions 
    } 

Сложность времени вложенных циклов равна количеству раз, когда выполняется самый внутренний оператор. Например, следующие образцы петля имеет О (N²) временной сложность:

for (int i = 1; i <=n; i += c) { 
     for (int j = 1; j <=n; j += c) { 
      // some O(1) expressions 
     } 
    } 

    for (int i = n; i > 0; i += c) { 
     for (int j = i+1; j <=n; j += c) { 
      // some O(1) expressions 
    } 

Время Сложность цикла рассматриваются как О (LOGN), если переменный цикл делится/умноженный на постоянной величину:

for (int i = 1; i <=n; i *= c) { 
     // some O(1) expressions 
    } 
    for (int i = n; i > 0; i /= c) { 
     // some O(1) expressions 
    } 

Теперь мы имеем:

for (int i = 0; i < n; i += 4) <----- runs n times 
    for (int j = 0; j < n; j++) <----- for every i again runs n times 
     for (int k = 1; k < j*j; k *= 2)` <--- now for every j it runs logarithmic times. 

Так сложность O (n²logm) где m is n², которое может быть упрощено до O (n²logn), поскольку n²logm = n²logn² = n² * 2logn ~ n²logn.

+0

Хотя он работает здесь, умножение сложностей «внутреннего цикла» с «внешней петлей» неверно. Рассмотрим: для (i = 1; i amit

+2

В метафоре это похоже на объяснение 2 + 2 + 2 = 6, потому что есть ** 3 ** 2 и ** 2 ** + 's, а 3 * 2 = 6. Это, очевидно, не получается при 3 + 3 + 3 = 6, так как снова - мы имеем ** 3 ** 3 и ** 2 ** +. – amit

+0

@amit Спасибо за разъяснение. –

7
  • С точки зрения j, внутренний цикл является O(log_2(j^2)) время, но синусоидальной log_2(j^2)=2log(j), это на самом деле O(log(j)).
  • Для каждой итерации среднего цикла, требуется O (журнал (к)) время (чтобы сделать внутренний контур), так что мы должны подвести:

    сумму {журнал (J) | J = 1, ..., п-1} журнал (1) + журнал (2) + ... + журнал (п-1) = лог ((п-1)!)

И так как log((n-1)!) находится в O((n-1)log(n-1)) = O(nlogn), мы можем заключить, что средняя средняя петля принимает O(nlogn) операций.

  • Обратите внимание, что оба среднего и внутренний контур не зависит от i, так получить общую сложность, мы можем просто умножить n/4 (число повторов внешнего контура) со сложностью среднего цикла, и получить:

    о (п/4 * NlogN) = O (N^2logn)

Таким образом, общая сложность этого кода O(n^2 * log(n))

+0

+1 Мне нравится обращение к известному «O (n * log (n)) = O (n!)'. Одна нота - я думаю, что лучше использовать операции вместо времени, например. 'внутренний цикл выполняет O (log_2 (j^2)) операции' –

+0

@IvayloStrandjev Спасибо за отзыв. Editted. – amit

Смежные вопросы