Я пытаюсь выяснить временную сложность (Big-O) функций и пытаюсь указать соответствующую причину.

Первая функция идет:

r = 0
# Assignment is constant time. Executed once. O(1)
for i in range(n):
    for j in range(i+1,n):
        for k in range(i,j):
            r += 1
            # Assignment and access are O(1). Executed n^3

Как это.

Я вижу, что это тройной вложенный цикл, поэтому он должен быть O (n ^ 3). но я думаю, что мои рассуждения здесь очень слабы. Я действительно не понимаю, что здесь происходит внутри тройного вложенного цикла.

Вторая функция:

i = n
# Assignment is constant time. Executed once. O(1)
while i>0:
    k = 2 + 2
    i = i // 2
    # i is reduced by the equation above per iteration.
    # so the assignment and access which are O(1) is executed
    # log n times ??

Я узнал, что этот алгоритм будет O (1). Но, как и в случае с первой функцией, я не вижу, что происходит в цикле while.

Может ли кто-нибудь подробно объяснить временную сложность двух функций? Спасибо!

6
zakels 18 Фев 2015 в 01:37
Вложенные циклы почти всегда квадратичны, если вы не выполняете какую-то постоянную работу, ваш второй пример - log(n).
 – 
Padraic Cunningham
18 Фев 2015 в 01:59
Спасибо. Во втором примере мы игнорируем часть i = n?
 – 
zakels
18 Фев 2015 в 02:26
I = n — это просто присваивание, после чего мы делим n пополам на каждой итерации, как если бы вы использовали поиск пополам.
 – 
Padraic Cunningham
18 Фев 2015 в 02:30
1
Первый цикл - O (n ^ 3), а не O (n ^ 2).
 – 
Jasper
18 Фев 2015 в 02:31
Эта ссылка может помочь: wiki.python.org/moin/TimeComplexity
 – 
Indranil Sinharoy
18 Фев 2015 в 04:02

2 ответа

Для такого простого случая вы могли бы найти количество итераций самого внутреннего цикла как функцию n точно:

sum_(i=0)^(n-1)(sum_(j=i+1)^(n-1)(sum_(k=i)^(j-1) 1)) = 1/6 n (n^2-1)

Т. е. Θ(n**3) временная сложность (см. Big Theta): предполагается, что r += 1 равно O(1), если r состоит из O(log n) цифр (в модели есть слова с log n битами).

Второй цикл еще проще: i //= 2 равно i >>= 1. n имеет Θ(log n) цифр, и каждая итерация отбрасывает одну двоичную цифру (сдвиг вправо), поэтому весь цикл имеет временную сложность Θ(log n), если предположить, что i >> 1 сдвиг log(n) цифр - операция O(1) (та же модель, что и в первом примере).

1
jfs 18 Фев 2015 в 03:53
Я пытался сделать эту штуку с WolframAlpha и потерпел неудачу, не могли бы вы показать шаги?
 – 
Jasper
19 Фев 2015 в 19:51
Нет никаких шагов, нажмите на ссылку, и вы должны увидеть результат.
 – 
jfs
19 Фев 2015 в 20:22
@Jasper: я забыл, как делать это вручную (компьютеры делают это слишком хорошо - если бы не списки покупок; я бы забыл, как писать). Найдите что-то вроде Как найти частичную сумму заданного ряда?, чтобы получить точный результат (преимущество в том, что TeX формулы отображаются там). Или, если вы хотите с нуля научиться находить частичные суммы.
 – 
jfs
20 Фев 2015 в 04:14
@Jasper: вот моя попытка сделать это вручную шаг за шагом. Ответ не тот ;) Вы можете повторить процесс и найти, где я допустил ошибку.
 – 
jfs
20 Фев 2015 в 05:22

Ну, во-первых, для первой функции временная сложность кажется ближе к O(N log N), потому что параметры каждого цикла каждый раз уменьшаются.

Кроме того, для второй функции время выполнения составляет O (log2 N). За исключением, скажем, i == n == 2. После одного прогона i равно 1. После другого i равно 0,5. После другого я составляет 0,25. И так далее... Я предполагаю, что вам нужен int(i).

Для строгого математического подхода к каждой функции вы можете перейти на https://www.coursera.org/course/ алгоритм. Это отличный курс для такого рода вещей. Я как-то поторопился в расчетах.

-4
bobhob314 18 Фев 2015 в 01:45
// в Python выполняет целочисленное деление
 – 
aganders3
18 Фев 2015 в 01:54
Как вторая функция O (log N)? Разве это не должно быть O (1), поскольку константа преобладает над логарифмической?
 – 
zakels
18 Фев 2015 в 02:23
"константа преобладает над логарифмической"? Нет.
 – 
Jasper
18 Фев 2015 в 02:26