Нужно просто учитывать количество бит для каждой операции и суммировать их. Конечно, мы сделаем небольшое округление, чтобы просто вещи, так как это не повлияет на ответ на ноту большой буквы O.
Таким образом, количество бит в x является потолком (log2 (x)) (т. Е. Следующее целое число выше логарифмической базы 2 x). Мы будем называть это число b для простоты. Это означает, что x больше 2^(b-1) и меньше 2^b. Итак, x^2 больше 2^(2 (b-1)) и меньше 2^(2b). Таким образом, мы будем предполагать, что x^2 имеет размер приблизительно 2b и что в общем случае x^n имеет размер nb. Это довольно близко к правильному, поскольку оно лежит между n (b-1) и nb.
Наше первое умножение займет время b * b = b^2. Наше второе умножение будет принимать 2b * b (так как x^2 имеет размер 2b, а x - размер b). Наше третье будет 3b * b (так как x^3 имеет размер 3b, а x - размер b). Итак, в общем случае наше n-е умножение будет nb * b.
Итак, наша сумма выглядит как b^2 + 2b^2 + 3b^2 + ... + (y-1) b^2. Мы можем разложить b^2, давая нам (b^2) (1 + 2 + 3 + ... + (y-1)). Для второго слагаемого 1 + 2 + 3 + ... + (y-1) мы можем использовать общую формулу: 1 + 2 + 3 + ... + n = n (n + 1)/2. Итак, мы получаем (b^2) (y-1) (y)/2.
На этом этапе мы очень близки к ответу, но мы хотим сделать две вещи: мы хотим выразить все в терминах x и y (а не b), и мы хотим уменьшить количество вещей, используя big-O обозначение для простоты. (y-1) (y)/2 можно упростить до O (y^2). b = потолок (log2 (x)), который можно упростить до O (log (x)). Подставляя назад, получаем O ((log (x))^2 * y^2).
Все это, конечно, при условии, что мы используем алгоритм, который выглядит следующим образом:
product = 1
for i = 1 to y
product = product * x
return product
Если мы делаем что-то более сложным и странным, как это одна:
xs = empty list
for i = 1 to y
xs.addItem(x)
while xs is not empty
num1 = xs.removeRandomItem
num2 = xs.removeRandomItem
xs.addItem(num1*num2)
return head(xs)
, тогда анализ времени становится более сложным. (Обратите внимание, что этот алгоритм также делает Y-1 умножения и получает правильный результат.)
Другой общий алгоритм для нахождения х^у является неоднократным алгоритм возведения в квадрате, который работает следующим образом:
result = 1
temp = x
while y>0
if y mod 2 = 1
result = result * temp
y = y - 1
temp = temp * temp
y = y/2
return result
Для этого мы делаем два умножения в каждом раунде, в которых участвуют два числа, каждый из которых имеет размер b (2^n), где n - число раундов, отсчитываемое от 0 (т. е. количество раз, которое мы прошли через цикл while). Таким образом, в круге n каждое умножение будет стоить b (2^n) * b (2^n) = (b^2) (2^(2n)). Но он касается только потолочных (log2 (y)) раундов. Таким образом, его время пробега было бы суммой (b^2) (2^0) + (b^2) (2^2) + (b^2) (2^4) + ... + (b^2) (2^(2 * потолок (log2 (у)))). Итак, снова мы можем разложить b^2, оставляя (b^2) (2^0 + 2^2 + 2^4 + ... + 2^(2 * потолок (log2 (y)))). Несмотря на сложность, весь второй член на самом деле равен O (y^2). Как только мы снова заменим b, получим, что это тоже O ((log (x))^2 * y^2). Таким образом, хотя этот алгоритм быстрее, когда умножения являются постоянными операциями времени, это не обязательно быстрее, когда мы работаем с BigIntegers или другими произвольными типами точности. Вот почему он чаще всего используется в ситуациях, таких как матричное умножение, где стоимость выполнения умножения является постоянной, но большой.
Err .. если одно умножение - одна операция ... –
Я добавил примечание к вопросу о том, что каждое умножение не является одной операцией, но также имеет собственное время работы. – Chetan
Я обновил свой ответ. Надеюсь, что это помогает –