Временная сложность вложенного цикла for

Мне нужно рассчитать временную сложность следующего кода:

for (i = 1; i <= n; i++)
{
  for(j = 1; j <= i; j++)
  {
   // Some code
  }
}

Это O (n ^ 2)?

10 ответов

Да, вложенные циклы - это один из способов быстро получить большую букву O.

Обычно (но не всегда) один цикл, вложенный в другой, вызывает O(n²).

Подумайте об этом, внутренний цикл выполняется i раз, для каждого значения i. Внешний цикл выполняется n раз.

таким образом, вы видите схему исполнения, подобную этой: 1 + 2 + 3 + 4 + ... + n раз

Следовательно, мы можем ограничить количество выполнений кода, сказав, что он, очевидно, выполняется более n раз (нижняя граница), но с точки зрения n, сколько раз мы выполняем код?

Ну, математически мы можем сказать, что он будет выполняться не более n² раз, что дает нам сценарий наихудшего случая и, следовательно, нашу оценку Big-Oh O(n²). (Для получения дополнительной информации о том, как мы можем математически сказать этот взгляд на серии Power)

Big-Oh не всегда точно измеряет объем работы, но обычно дает надежное приближение к худшему сценарию.


4 года спустя Редактировать: потому что этот пост, кажется, получает достаточное количество трафика. Я хочу более полно объяснить, как мы связали выполнение с O (n²), используя степенные ряды

С веб-сайта: 1+2+3+4...+n = (n² + n)/2 = n²/2 + n/2. Как же тогда мы превращаем это в O(n²)? Мы (в основном) говорим, что n² >= n²/2 + n/2. Это правда? Давайте сделаем простую алгебру.

  • Умножим обе стороны на 2, чтобы получить: 2n² >= n² + n?
  • Разверните 2n², чтобы получить:n² + n² >= n² + n?
  • Вычтите n² с обеих сторон, чтобы получить: n² >= n?

Должно быть ясно, что n² >= n (не строго больше, чем, из-за случая, когда n=0 или 1), предполагая, что n всегда является целым числом.

Фактическая сложность Big O немного отличается от того, что я только что сказал, но это суть. На самом деле, сложность Big O спрашивает, существует ли константа, которую мы можем применить к одной функции, чтобы она была больше другой, для достаточно большого ввода (см. Страницу википедии)

Быстрый способ объяснить это - это визуализировать.

если и i, и j от 0 до N, легко увидеть O(N^2)

O O O O O O O O
O O O O O O O O
O O O O O O O O
O O O O O O O O
O O O O O O O O
O O O O O O O O
O O O O O O O O
O O O O O O O O

в этом случае это:

O
O O
O O O
O O O O
O O O O O
O O O O O O
O O O O O O O
O O O O O O O O

Получается, что это 1/2 от N^2, который по-прежнему O(N^2)

Действительно, это O(n^2). Смотрите также очень похожий пример с тем же временем выполнения здесь.

Давайте проследим, сколько раз каждый цикл выполняется на каждой итерации.

      for (int i = 1; i <= n; i++){  // outer loop
    for (int j = 1; j <= i; j++){  // inner loop
        // some code
    }
}

В первой итерации внешнего цикла (i = 1) выполняется внутренний цикл once.

Во второй итерации внешнего цикла (i = 2) выполняется внутренний цикл twice.

На третьей итерации внешнего цикла (i = 3) выполняется внутренний цикл thrice.

Итак, на последней итерации внешнего цикла (i = n) выполняется внутренний цикл n times.

Таким образом, общее количество выполнений этого кода равно

1 + 2 + 3 + … + n

= (n(n + 1) / 2)(Формула суммы натуральных чисел)

= (((n^2) + n) / 2)

= O(n^2)

На 1-й итерации внешнего цикла (i = 1) внутренний цикл будет повторяться 1 раз. На 2-й итерации внешнего цикла (i = 2) внутренний цикл будет повторяться 2 раза. На 3-й итерации внешнего цикла. (i = 3), внутренний цикл будет повторяться 3 раза
,
,
На ЗАКЛЮЧИТЕЛЬНОЙ итерации внешнего цикла (i = n) внутренний цикл будет повторяться n раз

Таким образом, общее количество выполнений операторов во внутреннем цикле будет равно сумме целых чисел от 1 до n, которая равна:

((n)*n) / 2 = (n^2)/2 = O(n^2) times 

Да, временная сложность этого составляет O(n^2).

Как показали другие правильные ответы, результирующая сложность составляет O(n²). В первую очередь это O(n²/2), что сводится к O(n²). Вот почему /2 не имеет значения:

Важно понимать, что временная сложность относится не к скорости алгоритма, а к скорости изменения скорости относительно n. Скорость изменения.

Предположим, у нас есть два алгоритма:

  • A со сложностью O (n²)
  • B со сложностью O(n²/2)

Для размера ввода (n), равного 5, вы можете решить временную сложность следующим образом:

  • Для A - O(n²), что равно 25
  • Для B - O(n²/2), что равно 12,5.

Теперь для ввода размера 10 вы разрешите сложность, например:

  • Для A - O(n²), что равно 100
  • Для B - O(n²/2), что равно 50

В любом случае удвоение размера входных данных увеличило время выполнения в четыре раза. Это означает, что с точки зрения временной сложности O(n²/2) совпадает с O(n²). Как я уже сказал, временная сложность — это не мера того, сколько времени требуется для запуска алгоритма, а то, как это время изменяется в зависимости от размера входных данных.

Сначала рассмотрим циклы, в которых число итераций внутреннего цикла не зависит от значения индекса внешнего цикла. Например:

 for (i = 0; i < N; i++) {
     for (j = 0; j < M; j++) {
         sequence of statements
      }
  }

Внешний цикл выполняется N раз. Каждый раз, когда выполняется внешний цикл, внутренний цикл выполняется M раз. В результате операторы во внутреннем цикле выполняются в общей сложности N * M раз. Таким образом, общая сложность для двух циклов составляет O(N2).

Я думаю, что проще всего думать об этом так:

Внешний цикл выполняется n раз, и, по крайней мере, для n / 2 из этих итераций внутренний цикл выполняется не менее n / 2 раз. Поэтому общее число итераций внутреннего цикла составляет по меньшей мере п 2/4. Это O(n2)

Точно так же внешний цикл выполняется n раз, а на каждой итерации внутренний цикл выполняется не более n раз. Таким образом, общее количество итераций внутреннего цикла не превышает n 2 . Это тоже в O (n 2).

Внутренний цикл зависит от внешних циклов, а внутренний цикл выполняется 1 раз, что дает мне

для n = 5, если i = 1, внутренний цикл выполняется 1 раз 1 = 1

если i = 2 внутренние петли выполняются 2 раза 1 + 2 = 3

если i = 3 внутренние петли выполняются 3 раза 1 + 2 + 3 = 6

если i = 4 внутренние петли выполняются 4 раза 1 + 2 + 3 + 4 = 10

если i = 5, внутренние петли выполняются 5 раз 1 + 2 + 3 + 4 + 5 = 15

Сверху мы можем знать, что n (n + 1) / 2

Итак, O(n *(n + 1)) / 2 = O(n2 / 2 + n / 2) = O(n2 / 2) + O(n / 2)

Я не очень разбираюсь в алгоритмах анализа, поэтому не стесняйтесь исправлять мой ответ.

Другие вопросы по тегам