Один из самых каверзных вопросов в интервью.
Поменяйте местами значения двух переменных, например a=10
и b=15
.
Обычно, чтобы поменять местами значения двух переменных, нам нужна третья переменная, например:
temp=a;
a=b;
b=temp;
Теперь необходимо поменять местами значения двух переменных без использования третьей переменной.
Ответы:
Использование алгоритма обмена xor
Зачем тест?
Тест должен убедиться, что x и y имеют разные ячейки памяти (а не разные значения). Это потому что
(p xor p) = 0
если и x, и y совместно используют одну и ту же ячейку памяти, когда один из них установлен в 0, оба устанавливаются в 0. Когда оба * x и * y равны 0, все другие операции xor для * x и * y будут равны 0 (поскольку они одинаковы), что означает, что функция установит для * x и * y значение 0.Если у них одинаковые значения, но не одно и то же место в памяти, все работает должным образом.
Следует ли это использовать?
В общих случаях нет. Компилятор оптимизирует временную переменную и, учитывая, что замена является обычной процедурой, он должен вывести оптимальный машинный код для вашей платформы.
Возьмем, к примеру, эту программу быстрого тестирования, написанную на C.
Скомпилировано с использованием:
Версия xor принимает
Где в качестве версии с временной переменной принимает:
источник
общая форма:
однако вы должны потенциально остерегаться переполнения, а также не все операции имеют инверсию, которая хорошо определена для всех значений, определенных для операции. например, * и / работают, пока A или B не станут 0
xor особенно приятен, поскольку он определен для всех целых чисел и является его собственным обратным
источник
источник
a+b
переполнится?int
,unsigned short
...), он все еще работает, в конце концов, даже с переливом, потому что если а + Ь переполняется, то а - Ь будет Underflow. С этими базовыми целочисленными типами значения просто меняются местами.unsigned
целочисленных типов нормально и работает всегда. Для подписанных типов это вызовет неопределенное поведение при переполнении.Пока никто не предлагал использовать
std::swap
.Я не использую никаких временных переменных и в зависимости от типа
a
иb
реализации может иметь специализацию, которая тоже не работает. Реализация должна быть написана с учетом того, уместен ли «трюк». Нет смысла повторять догадки.В более общем плане я, вероятно, хотел бы сделать что-то подобное, поскольку это будет работать для типов классов, позволяющих ADL найти лучшую перегрузку, если это возможно.
Конечно, реакция интервьюера на такой ответ может многое сказать о вакансии.
источник
std::
пользователемswap
реализаций для определяемых пользователем типов также доступны для вызова (это означает, что «он будет работать для типов классов, позволяющих ADL найти лучшую перегрузку, если это возможно»).std::swap
использует дополнительную временную память в своей реализации нет? cplusplus.com/reference/utility/swapКак уже отмечалось в manu, алгоритм XOR - популярный алгоритм, который работает для всех целочисленных значений (включая указатели, если повезет и приведение типов). Для полноты картины хотелось бы упомянуть еще об одном менее мощном алгоритме с добавлением / вычитанием:
Здесь вы должны быть осторожны с переполнением / недостаточным заполнением, но в остальном все работает так же хорошо. Вы даже можете попробовать это с числами с плавающей запятой / удвоением, если XOR для них не разрешен.
источник
std::swap()
? Конечно, вы можете преобразовывать указатели в целые числа и обратно (при условии, что существует достаточно большой целочисленный тип, что не гарантируется), но это не то, что вы предлагали; вы подразумевали, что указатели - это целые числа, а не то, что они могут быть преобразованы в целые числа. Да, принятый ответ не будет работать для указателей. Использование ответа Чарльза Бейлиstd::swap
действительно единственно правильное.std::swap
можно реализовать без использования третьей переменной.Глупые вопросы заслуживают соответствующих ответов:
Единственное хорошее использование
register
ключевого слова.источник
Обмен двух чисел с использованием третьей переменной будет таким:
Замена двух чисел без использования третьей переменной
источник
источник
cout << "Enter the two no=:"
я ожидал прочитатьcout << "Now enter the two no in reverse order:"
a+b
илиa-b
переполнении. Такжеvoid main()
недействителен и<conio.h>
нестандартен.Поскольку исходное решение:
Вы можете сделать его двухслойным, используя:
Затем сделайте его однострочным, используя:
источник
y
читается и записывается одним и тем же выражением без промежуточной точки последовательности.Если вы немного измените вопрос о двух регистрах сборки вместо переменных, вы также можете использовать
xchg
операцию как одну опцию, а операцию стека как другую.источник
xchg
операции вы имеете в виду? В вопросе не была указана архитектура процессора.Учтите
a=10
, чтоb=15
:источник
a=10
иb=1.5
.Обновление: здесь мы получаем от пользователя два целых числа. Затем мы используем побитовую операцию XOR, чтобы поменять их местами.
Скажем , у нас есть два целых числа
a=4
и ,b=9
а затем:источник
Вот еще одно решение, но с одним риском.
код:
любое значение в местоположении a + 1 будет переопределено.
источник
*(&a+1)
вполне может бытьb
.void main()
является недействительным.<conio.h>
нестандартно (и вы им даже не пользуетесь).Конечно, ответ C ++ должен быть
std::swap
.Однако в следующей реализации
swap
:Или, как однострочный:
источник
источник
это правильный алгоритм обмена XOR
вы должны убедиться, что ячейки памяти разные, а также фактические значения, потому что A XOR A = 0
источник
Вы можете сделать .... простым способом ... в пределах одной строки Логика
или
источник
b
и читается, и модифицируется в одном выражении без промежуточной точки последовательности.источник
Лучшим ответом было бы использовать XOR, и использовать его в одной строке было бы здорово.
x, y - переменные, и запятая между ними вводит точки последовательности, поэтому они не зависят от компилятора. Ура!
источник
Давайте посмотрим на простой пример c, чтобы поменять местами два числа без использования третьей переменной.
программа 1:
Вывод:
До свопа a = 10 b = 20 После свопа a = 20 b = 10
Программа 2: Использование * и /
Давайте посмотрим на другой пример, чтобы поменять местами два числа с помощью * и /.
Вывод:
До свопа a = 10 b = 20 После свопа a = 20 b = 10
Программа 3: Использование побитового оператора XOR:
Побитовый оператор XOR можно использовать для обмена двумя переменными. XOR двух чисел x и y возвращает число, в котором все биты равны 1, если биты x и y различаются. Например, XOR для 10 (в двоичном формате 1010) и 5 (в двоичном формате 0101) равно 1111, а XOR для 7 (0111) и 5 (0101) равно (0010).
Вывод:
После обмена: x = 5, y = 10
Программа 4:
Пока никто не предлагал использовать std :: swap.
Я не использую какие-либо временные переменные, и в зависимости от типа a и b реализация может иметь специализацию, которой тоже нет. Реализация должна быть написана с учетом того, уместен ли «трюк».
Проблемы с вышеуказанными методами:
1) Подход, основанный на умножении и делении, не работает, если одно из чисел равно 0, поскольку произведение становится 0 независимо от другого числа.
2) Оба арифметических решения могут вызвать арифметическое переполнение. Если x и y слишком велики, сложение и умножение могут выйти за пределы целочисленного диапазона.
3) Когда мы используем указатели на переменную и выполняем замену функций, все вышеперечисленные методы не работают, когда оба указателя указывают на одну и ту же переменную. Давайте посмотрим, что произойдет в этом случае, если оба будут указывать на одну и ту же переменную.
// Побитовый метод на основе XOR
// Метод на основе арифметики
Посмотрим на следующую программу.
Выход :
После обмена (& x, & x): x = 0
Замена переменной самой собой может потребоваться во многих стандартных алгоритмах. Например, посмотрите эту реализацию QuickSort, где мы можем поменять местами переменную с собой. Вышеупомянутой проблемы можно избежать, поставив условие перед заменой.
Выход :
После обмена (& x, & x): x = 10
источник
Может быть, не по теме, но если вы знаете, что меняете одну переменную между двумя разными значениями, вы можете выполнить логику массива. Каждый раз, когда эта строка кода запускается, она меняет значение между 1 и 2.
источник
Вы могли сделать:
Или используйте make_tuple при замене более двух переменных:
Но я не уверен, использует ли std :: tie внутреннюю временную переменную или нет!
источник
В javascript:
Обратите внимание на время выполнения обоих вариантов.
Запустив этот код, я измерил его.
Как вы можете видеть (и как многие говорили), замена на месте (xor) занимает намного больше времени, чем другой вариант с использованием временной переменной.
источник
В R отсутствует параллельное задание, предложенное Эдсгером В. Дейкстра в «Дисциплина программирования» , 1976, глава 4, стр.29. Это позволило бы найти элегантное решение:
источник
Это очень просто, но может вызвать предупреждение.
источник
b=a
выполняется ли это до или послеa + b
.однострочное решение для замены двух значений на языке c.
источник
источник