Как поменять местами два числа

Как программист, вы наверняка не раз сталкивались с задачей поменять местами два значения. Это одна из самых распространённых операций при написании кода.
Существует несколько подходов: с помощью временной переменной, арифметики, побитовых операций и языковых особенностей. Ниже — подробный обзор методов с реализациями на C++, Python и JavaScript, список когда какой метод применять, возможные подводные камни и проверки.
Ключевые варианты замены значений
- Временная переменная — самый простой и понятный способ.
- Арифметика (сложение/вычитание) — работает без дополнительной памяти, но опасна при переполнении.
- Арифметика (умножение/деление) — не применяйте, если есть нулевые значения; риск деления на ноль.
- Побитовый XOR — работает для целых типов, но требует осторожности при совпадающих ссылках/алиасинге.
- Языковые конструкции (многократное присваивание, tuple-unpacking) — самый читаемый в языках, где доступны.
Как поменять местами два числа с помощью временной переменной
Использование временной переменной — самый очевидный и безопасный способ. Шаги:
- Присвоить значение первой переменной во временную.
- Присвоить значение второй переменной первой.
- Присвоить значение временной переменной второй.
Пример: num1 = 80, num2 = 50 (до обмена).
После шага 1: num1 = 80, num2 = 50, temp = 80.
После шага 2: num1 = 50, num2 = 50, temp = 80.
После шага 3: num1 = 50, num2 = 80.
C++: обмен через временную переменную
#include
using namespace std;
// Функция меняет два числа местами
// с помощью временной переменной
void swapNums(int num1, int num2)
{
// Печать значений до обмена
cout << "До обмена: " << endl;
cout << "num1 = " << num1 << ", num2 = " << num2 << endl;
// Обмен с помощью временной переменной "temp"
int temp = num1;
num1 = num2;
num2 = temp;
// Печать значений после обмена
cout << "После обмена: " << endl;
cout << "num1 = " << num1 << ", num2 = " << num2 << endl;
}
// Точка входа
int main()
{
swapNums(80, 50);
return 0;
} Вывод:
До обмена:
num1 = 80, num2 = 50
После обмена:
num1 = 50, num2 = 80Python: обмен через временную переменную
# Функция меняет два числа местами
# с помощью временной переменной
def swapNums(num1, num2):
# Печать значений до обмена
print("До обмена:")
print("num1:", num1, ", num2:", num2)
# Обмен с помощью временной переменной "temp"
temp = num1
num1 = num2
num2 = temp
# Печать значений после обмена
print("После обмена:")
print("num1:", num1, ", num2:", num2)
# Вызов
swapNums(80, 50)Вывод:
До обмена:
num1 = 80, num2 = 50
После обмена:
num1 = 50, num2 = 80JavaScript: обмен через временную переменную
Вывод:
До обмена:
num1 = 80, num2 = 50
После обмена:
num1 = 50, num2 = 80Как поменять местами два числа с помощью арифметики (сложение и вычитание)
Идея: сначала вычислить сумму, затем восстановить отдельные значения через вычитание.
Алгоритм:
- num1 = num1 + num2
- num2 = num1 - num2
- num1 = num1 - num2
Недостатки: возможное переполнение при больших числах; не годится для типов с ограниченным диапазоном (например, 32‑бит int). Также опасно использовать с плавающей точкой из‑за потери точности.
C++: арифметика (+, -)
#include
using namespace std;
// Обмен с помощью арифметики (+, -)
void swapNums(int num1, int num2)
{
cout << "До обмена: " << endl;
cout << "num1 = " << num1 << ", num2 = " << num2 << endl;
// Обмен с помощью арифметических операций
num1 = num1 + num2;
num2 = num1 - num2;
num1 = num1 - num2;
cout << "После обмена: " << endl;
cout << "num1 = " << num1 << ", num2 = " << num2 << endl;
}
int main()
{
swapNums(80, 50);
return 0;
} Python: арифметика (+, -)
# Обмен с помощью арифметики (+, -)
def swapNums(num1, num2):
print("До обмена:")
print("num1:", num1, ", num2:", num2)
num1 = num1 + num2
num2 = num1 - num2
num1 = num1 - num2
print("После обмена:")
print("num1:", num1, ", num2:", num2)
swapNums(80, 50)JavaScript: арифметика (+, -)
Вывод для всех примеров аналогичен: num1 и num2 поменялись местами.
Как поменять местами два числа с помощью арифметики (умножение и деление)
Шаги:
- num1 = num1 * num2
- num2 = num1 / num2
- num1 = num1 / num2
Почему это плохо: если один из чисел равен 0, продукт будет 0 и восстановление невозможно; при делении возможны ошибки (деление на ноль). Этот метод не рекомендуется для общего использования.
Как поменять местами два числа с помощью побитовых операций (XOR)
Побитовый XOR позволяет обменять целые значения без дополнительной памяти и без риска переполнения (как при сложении), но он применим только к целочисленным типам и требует осторожности при том же объекте/алиасинге.
Правило: нельзя безопасно применять, если num1 и num2 указывают на одну и ту же переменную (в некоторых реализациях это может обнулить значение).
C++: XOR
#include
using namespace std;
// Обмен с помощью XOR
void swapNums(int num1, int num2)
{
cout << "До обмена: " << endl;
cout << "num1 = " << num1 << ", num2 = " << num2 << endl;
num1 = num1 ^ num2;
num2 = num1 ^ num2;
num1 = num1 ^ num2;
cout << "После обмена: " << endl;
cout << "num1 = " << num1 << ", num2 = " << num2 << endl;
}
int main()
{
swapNums(80, 50);
return 0;
} Python: XOR (только для целых чисел)
# Обмен с помощью XOR
def swapNums(num1, num2):
print("До обмена:")
print("num1:", num1, ", num2:", num2)
num1 = num1 ^ num2
num2 = num1 ^ num2
num1 = num1 ^ num2
print("После обмена:")
print("num1:", num1, ", num2:", num2)
swapNums(80, 50)JavaScript: XOR
Вывод тот же: значения поменялись местами.
Однострочные решения (когда язык поддерживает)
Если язык поддерживает множественное присваивание, это самый читаемый и безопасный способ.
C++ (одно выражение с XOR)
#include
using namespace std;
int main()
{
int num1 = 80, num2 = 50;
cout << "До обмена: " << endl;
cout << "num1 = " << num1 << ", num2 = " << num2 << endl;
// Однострочный обмен (XOR)
num1 = num1 ^ num2, num2 = num1 ^ num2, num1 = num1 ^ num2;
cout << "После обмена: " << endl;
cout << "num1 = " << num1 << ", num2 = " << num2 << endl;
return 0;
} Python (многократное присваивание — рекомендуемый вариант)
num1 = 80
num2 = 50
print("До обмена:")
print("num1:", num1, ", num2:", num2)
# Однострочный обмен — самый читаемый
num1, num2 = num2, num1
print("После обмена:")
print("num1:", num1, ", num2:", num2)JavaScript (однострочный с XOR)
Примечание: в JavaScript и C++ подобные хитрые трюки снижают читаемость и могут запутать сопровождающих код.
Когда методы не годятся — подводные камни и примеры ошибок
- Арифметика (сложение) — риск переполнения при больших целых числах.
- Арифметика (умножение/деление) — деление на ноль и потеря информации при нулях.
- XOR — некорректно работает при том, что оба имени ссылаются на один и тот же объект/адрес; не применимо к вещественным типам.
- Однострочные трюки — ухудшают читаемость и тестируемость; лучше избегать в командном коде.
Пример ошибки: если num1 и num2 — ссылки на один и тот же контейнер (например, два имени, указывающие на один объект в Python), некоторые трюки могут привести к неожиданному результату.
Альтернативные подходы и рекомендации
- Всегда выбирайте читаемость: временная переменная или языковые конструкции (tuple unpacking) чаще всего лучше.
- Для критичных по производительности участков сначала измерьте: операции присваивания дешевы, а оптимизация в ущерб понятности редко оправдана.
- Если работаете с большими числами или фиксированной разрядностью, учитывайте переполнение и используйте безопасные типы (например, 64‑бит).
Быстрые эвристики (mental models)
- Если нужен простой и очевидный код — используйте temp.
- Если язык поддерживает множественное присваивание — используйте его.
- Если важно избежать дополнительной памяти и вы оперируете целыми без совпадающих ссылок — можно использовать XOR.
- Никогда не используйте умножение/деление, если есть вероятность нулевых значений.
Краткий глоссарий (1 строка на термин)
- XOR: побитовая операция исключающего ИЛИ для целых чисел.
- Множественное присваивание: одновременное присваивание нескольким переменным (например, num1, num2 = num2, num1).
- Переполнение: ситуация, когда значение выходит за пределы представимого диапазона типа.
Чек-лист для разработчика перед публикацией изменения
- Код понятен ревьюеру без комментариев.
- Нет риска переполнения или деления на ноль.
- Нет скрытого алиасинга переменных.
- Добавлены тесты для граничных случаев (ноль, отрицательные, большие значения).
Критерии приёмки
- Функция корректно меняет местами любые допустимые входные значения.
- Нет побочных эффектов для внешних переменных или глобального состояния.
- Тесты покрывают граничные случаи и ожидаемые ошибки.
Краткое резюме
Замена значений — базовая операция с множеством корректных способов. Для большинства задач выбирайте читаемость и предсказуемость: временная переменная или встроенные языковые механизмы (например, множественное присваивание в Python). Оптимизации через арифметику или побитовые трюки применяйте только при острой необходимости и после учёта всех рисков.
Важно: не придумывайте оптимизаций без метрики — сначала убедитесь, что это действительно узкое место.
Если хотите посмотреть полный исходный код, упомянутый в статье, проверьте соответствующий репозиторий на GitHub.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone