- 6 августа 2025
- 4 минуты
- 506
Преимущества и недостатки алгоритма Евклида в Python
Статью подготовили специалисты образовательного сервиса Zaochnik.
Алгоритм Евклида — это традиционный метод для вычисления наибольшего общего делителя (НОД) двух целых чисел.
Алгоритмы решения задачи
Рассмотрим задачу нахождения НОД для двух натуральных чисел. Даны два натуральных числа `a` и `b`, и необходимо найти такое наибольшее число `d`, которое делит оба числа.
Существует несколько способов решения этой задачи.
Наивный алгоритм
Наивный метод заключается в переборе всех чисел от 1 до `min(a, b)` и проверке делимости чисел `a` и `b`. После проверки выбирается наибольшее число, которое делит оба числа. Такая реализация имеет временную сложность O(min(a, b)).
Оптимизация перебора
Перебор всех чисел до `min(a, b)` можно оптимизировать, проверяя только делители одного из чисел. Эта оптимизация позволяет уменьшить время выполнения до O(√min(a, b)), применяя идеи, схожие с алгоритмом проверки на простоту.
Алгоритм Евклида
Алгоритм Евклида позволяет решить эту задачу гораздо эффективнее, основываясь на следующем свойстве:
НОД(a, b) = НОД(a - b, b)
Это свойство легко доказать. Если `d` — общий делитель `a` и `b`, то `d` также будет делителем `a - b`, и наоборот. Соответственно, множества общих делителей для пар `(a, b)` и `(a - b, b)` совпадают, следовательно, НОД тоже будет одинаковым.
Примеры реализации конкретной задачи
Рассмотрим НОД чисел 36 и 24:
- Шаг 1: (36 - 24) = 12
- Получаем пару 24 и 12.
- Шаг 2: (24 - 12) = 12
- Теперь числа равны. Таким образом, НОД(36, 24) = 12.
Циклическая реализация
Алгоритм можно записать с использованием цикла `while` следующим образом:
```python
def nod(a, b):
while a != 0 and b != 0:
if a > b:
a = a - b
else:
b = b - a
return max(a, b)
```
Рекурсивная реализация
Также алгоритм можно реализовать рекурсивно:
```python
def nod(a, b):
if a == 0 or b == 0:
return max(a, b)
else:
if a > b:
return nod(a - b, b)
else:
return nod(a, b - a)
```
Вышеуказанная реализация часто оказывается неэффективной, так как много раз выполняются вычитания. Например, если взять числа 500000 и 1000, алгоритм выполнит 500 миллионов вычитаний.
Оптимизированный алгоритм
Чтобы улучшить эффективность, можно заменить вычитание на операцию взятия остатка:
```python
def nod(a, b):
if a == 0 or b == 0:
return max(a, b)
else:
if a > b:
return nod(a % b, b)
else:
return nod(a, b % a)
```
Или в циклическом виде:
```python
def nod(a, b):
while a != 0 and b != 0:
if a > b:
a = a % b
else:
b = b % a
return max(a, b)
```
Простой алгоритм
Алгоритм можно записать еще проще. Предположим, что `b` меньше `a`:
```python
def nod(a, b):
if b == 0:
return a
else:
return nod(b, a % b)
```
Или в циклическом виде:
```python
def nod(a, b):
while b != 0:
a, b = b, a % b
return a
```
Этот подход сохраняет два инварианта: `a` и `b` остаются неотрицательными, а НОД не изменяется. Алгоритм будет корректен и в случае, когда одно из чисел равно 0, и на первом шаге значения `a` и `b` просто поменяются местами.
Алгоритм Евклида
Алгоритм Евклида работает наиболее медленно, когда на вход подаются два числа, являющиеся соседними членами последовательности Фибоначчи. Известно, что n-й член последовательности Фибоначчи можно вычислить по формуле:
где
- золотое сечение.
Таким образом, сложность алгоритма Евклида составляет O(log(min(a, b))).