Échange de deux valeurs de variable sans utiliser de troisième variable

104

Une des questions très délicates posées lors d'une interview.

Échangez les valeurs de deux variables comme a=10et b=15.

Généralement, pour échanger deux valeurs de variables, nous avons besoin d'une troisième variable comme:

temp=a;
a=b;
b=temp;

Maintenant, l'exigence est de permuter les valeurs de deux variables sans utiliser la 3e variable.

Muhammad Akhtar
la source
76
Sensationnel. Une question d'entrevue mal choisie à mon humble avis. C'est une technique qui est rarement, voire jamais, utile dans la pratique. Il y a de fortes chances que cela ne fasse que confondre l'optimiseur du compilateur, ce qui entraînera un code moins efficace qu'un "échange temporaire". À moins que cet endroit où vous interviewiez ne s'implique dans des choses très lourdes en mathématiques (pensez: développement d'algorithmes de cryptage ou autre), je ne peux imaginer aucune bonne raison de poser une telle question.
Dan Moulding
10
En effet, cette question ne vous dit rien d'autre que si le candidat connaît cette astuce particulière qui est à peu près inutile dans le code de production. Je suppose que vous pourriez rencontrer un sorcier occasionnel qui le découvre à la volée, mais des gens comme ça qui ne connaissent pas déjà le truc sont susceptibles d'être assez rares.
ceo
2
Peut-être veulent-ils éliminer les personnes qui pensent que connaître de telles astuces est ce qui fait un bon programmeur? De plus, lorsque vous lisez à propos du xor-trick, faites attention au moment où il échouera (ce que l'OMI le rend pratiquement inutile pour l'échange d'entiers à usage général).
UncleBens

Réponses:

155

Utilisation de l' algorithme d'échange xor

void xorSwap (int* x, int* y) {
    if (x != y) { //ensure that memory locations are different
       *x ^= *y;
       *y ^= *x;
       *x ^= *y;
    }
}


Pourquoi le test?

Le test consiste à s'assurer que x et y ont des emplacements mémoire différents (plutôt que des valeurs différentes). Ceci est dû au fait que (p xor p) = 0et si x et y partagent le même emplacement mémoire, quand l'un est défini sur 0, les deux sont définis sur 0. Lorsque * x et * y sont tous deux 0, toutes les autres opérations xor sur * x et * y seront égales 0 (car ils sont identiques), ce qui signifie que la fonction définira à la fois * x et * y sur 0.

S'ils ont les mêmes valeurs mais pas le même emplacement mémoire, tout fonctionne comme prévu

*x = 0011
*y = 0011
//Note, x and y do not share an address. x != y

*x = *x xor *y  //*x = 0011 xor 0011
//So *x is 0000

*y = *x xor *y  //*y = 0000 xor 0011
//So *y is 0011

*x = *x xor *y  //*x = 0000 xor 0011
//So *x is 0011


Cela devrait-il être utilisé?

Dans les cas généraux, non. Le compilateur optimisera la variable temporaire et étant donné que la permutation est une procédure courante, il devrait générer le code machine optimal pour votre plate-forme.

Prenons par exemple ce programme de test rapide écrit en C.

#include <stdlib.h>
#include <math.h>

#define USE_XOR 

void xorSwap(int* x, int *y){
    if ( x != y ){
        *x ^= *y;
        *y ^= *x;
        *x ^= *y;
    }
}

void tempSwap(int* x, int* y){
    int t;
    t = *y;
    *y = *x;
    *x = t;
}


int main(int argc, char* argv[]){
    int x = 4;
    int y = 5;
    int z = pow(2,28); 
    while ( z-- ){
#       ifdef USE_XOR
            xorSwap(&x,&y);
#       else
            tempSwap(&x, &y);
#       endif
    }
    return x + y;    
}

Compilé avec:

gcc -Os main.c -o swap

La version xor prend

real    0m2.068s
user    0m2.048s
sys  0m0.000s

Où prend la version avec la variable temporaire:

real    0m0.543s
user    0m0.540s
sys  0m0.000s
Yacoby
la source
1
Cela pourrait valoir la peine d'expliquer le pourquoi du test (c.-à-d. Que l'approche triple xor échoue horriblement si x et y font référence au même objet).
dmckee --- ex-moderator chaton
1
Je ne sais pas comment cela a obtenu autant de votes positifs alors que le code est si cassé. Les deux swaps dans le segment de code testé sont complètement incorrects. Regardez de près.
SoapBox
@SoapBox: Très bon point! Le XOR swap zéros x & laisse y intact, et le temp swap laisse les deux avec la valeur de x. Oups!
Drew Hall le
4
@SoapBox Bonne prise. Corrigé et retesté et je n'obtiens aucune différence majeure dans les horaires.
Yacoby
4
Le questionneur a dit deux variables, pas des ints. : P
Plumenator
93

la forme générale est:

A = A operation B
B = A inverse-operation B
A = A inverse-operation B 

Cependant, vous devez potentiellement faire attention aux débordements et toutes les opérations n'ont pas non plus un inverse bien défini pour toutes les valeurs que l'opération est définie. par exemple * et / fonctionnent jusqu'à ce que A ou B soit 0

xor est particulièrement agréable car il est défini pour tous les entiers et est son propre inverse

jk.
la source
XOR (X, X) == 0, donc xor fonctionne pour les entiers SAUF lorsque les deux valeurs échangées sont égales. Je ne suis pas le premier à le signaler et trop de gens l'ont dit (ici et ailleurs) pour désigner quelqu'un pour le crédit.
AlanK
85
a = a + b
b = a - b // b = a
a = a - b
Dor
la source
16
Et si les a+bdébordements?
Alok Singhal du
2
@Alok: Cela n'est pas pris en considération, donc ce n'est pas pratique :)
Dor
4
Si a et b sont du même type d'entiers basiques et dimensionnés (comme int,, unsigned short...), cela fonctionne toujours à la fin, même avec un débordement, car si a + b déborde, alors a - b débordera. Avec ces types d'entiers de base, les valeurs survolent simplement.
Patrick Johnmeyer
11
En C, utiliser ceci sur unsigneddes types entiers est OK et fonctionne toujours. Sur les types signés, cela invoquerait un comportement indéfini en cas de débordement.
jpalecek
2
@Shahbaz: Même si les entiers signés sont stockés dans le complément à 2, le comportement en cas de dépassement n'est toujours pas défini.
Keith Thompson
79

Personne n'a encore suggéré d'utiliser std::swap.

std::swap(a, b);

Je n'utilise aucune variable temporaire et selon le type de aet bl'implémentation peut avoir une spécification qui ne l'est pas non plus. L'implémentation doit être écrite en sachant si une «astuce» est appropriée ou non. Il ne sert à rien d'essayer de remettre en question.

Plus généralement, je voudrais probablement faire quelque chose comme ça, car cela fonctionnerait pour les types de classe permettant à ADL de trouver une meilleure surcharge si possible.

using std::swap;
swap(a, b);

Bien entendu, la réaction de l'intervieweur à cette réponse pourrait en dire long sur le poste vacant.

CB Bailey
la source
bien sûr, en C ++, le swap 0x utilisera des références rvalue, ce sera donc encore mieux!
jk.
16
Tout le monde veut montrer le xor brillant ou un autre truc qu'ils ont appris, avec diverses mises en garde sur la façon de l'utiliser, mais c'est indubitablement la meilleure réponse.
2
pourquoi pas std :: swap (a, b); ? Je veux dire pourquoi l'utilisation?
Dinaiz
2
@Dinaiz sans les implémentations std::définies swappar l'utilisateur pour les types définis par l'utilisateur sont également disponibles pour appeler (c'est ce que signifie «cela fonctionnerait pour les types de classe permettant à ADL de trouver une meilleure surcharge si possible»).
Kyle Strand
std::swaputilise de la mémoire temporaire supplémentaire dans son implémentation non? cplusplus.com/reference/utility/swap
Ninja
19

Comme déjà noté par manu, l'algorithme XOR est un algorithme populaire qui fonctionne pour toutes les valeurs entières (qui comprend alors des pointeurs, avec un peu de chance et de casting). Par souci d'exhaustivité, je voudrais mentionner un autre algorithme moins puissant avec addition / soustraction:

A = A + B
B = A - B
A = A - B

Ici, vous devez faire attention aux débordements / sous-débits, mais sinon cela fonctionne tout aussi bien. Vous pouvez même essayer ceci sur les flottants / doubles dans le cas où XOR n'est pas autorisé sur ceux-ci.

Vilx-
la source
" toutes les valeurs entières (y compris les pointeurs alors) " - Quoi? Non, les pointeurs ne sont pas des entiers et vous ne pouvez pas xor des valeurs de pointeur. Vous ne pouvez pas non plus xor des valeurs à virgule flottante. Mais la méthode d'addition / soustraction a un comportement indéfini (pour les types à virgule flottante ou signée) en cas de dépassement de capacité ou de dépassement inférieur, peut perdre en précision pour les virgule flottante et ne peut pas être appliquée aux pointeurs ou à d'autres types non numériques.
Keith Thompson
@KeithThompson - OK, la perte de précision pour les virgules flottantes est vraie, mais selon les circonstances, cela pourrait être acceptable. En ce qui concerne les pointeurs - eh bien, je n'ai jamais entendu parler d'un compilateur / plate-forme où les pointeurs ne pouvaient pas être librement convertis en nombres entiers et inversement (en prenant soin de choisir un entier de la bonne taille, bien sûr). Mais alors, je ne suis pas un expert C / C ++. Je sais que cela va à l'encontre de la norme, mais j'avais l'impression que ce comportement est assez cohérent à travers ... tout.
Vilx-
1
@ Vilx-: Pourquoi une perte de précision serait-elle acceptable alors qu'il est si facile de l'éviter en utilisant une variable temporaire - ou std::swap()? Bien sûr, vous pouvez convertir des pointeurs en nombres entiers et inversement (en supposant qu'il existe un type entier suffisamment grand, ce qui n'est pas garanti), mais ce n'est pas ce que vous avez suggéré; vous avez laissé entendre que les pointeurs sont des entiers et non pas qu'ils peuvent être convertis en entiers. Oui, la réponse acceptée ne fonctionnera pas pour les pointeurs. La réponse de Charles Bailey utilisant std::swapest vraiment la seule correcte.
Keith Thompson
1
Tout d'abord, la question était de savoir "comment échanger sans utiliser une troisième variable" et la raison invoquée était "une question d'entrevue". Je viens de donner une autre réponse possible. Deuxièmement, OK, je m'excuse d'avoir laissé entendre que les pointeurs sont des entiers. J'ai mis à jour la réponse pour être, espérons-le, plus explicite et correcte. Veuillez me corriger si je me trompe toujours (ou mettre à jour la réponse vous-même). Troisièmement, j'ai supprimé la partie concernant la réponse acceptée. Il n'utilise pas de casse pointeur vers entier n'importe où et cela fonctionne correctement (pour autant que je sache).
Vilx-
@KeithThompson: La question pourrait être modifiée pour savoir comment std::swapmettre en œuvre sans utiliser une troisième variable.
jxh
10

Les questions stupides méritent des réponses appropriées:

void sw2ap(int& a, int& b) {
  register int temp = a; // !
  a = b;
  b = temp;
}

Le seul bon usage du registermot - clé.

MSalters
la source
1
Un objet déclaré avec un registre de classe de stockage n'est-il pas une "variable"? De plus, je ne suis pas convaincu que ce soit une bonne utilisation du registre, car si votre compilateur ne peut pas déjà l'optimiser, quel est l'intérêt d'essayer, vous devriez soit accepter les déchets que vous obtenez ou écrire l'assemblage vous-même ;-) Mais comme vous dites, une question douteuse mérite une réponse douteuse.
Steve Jessop
1
Presque tous les compilateurs modernes ignorent la classe de stockage de registre, car ils ont une bien meilleure idée de ce qui est fréquemment consulté que vous.
ceo
6
Notez que cette réponse est destinée aux intervieweurs, pas aux compilateurs. Il profite surtout du fait que le genre d'intervieweurs qui posent ce genre de question ne comprend pas vraiment le C ++. Donc, ils ne peuvent pas rejeter cette réponse. (et il n'y a pas de réponse standard; ISO C ++ parle d'objets et non de variables).
MSalters
Ah, je te comprends. Je cherchais dans le standard C la mention de variable en tant que nom, et pas seulement de non-const. J'en ai trouvé un dans n1124, dans la section sur les boucles for définissant la portée des «variables» déclarées dans l'initialiseur. Ensuite, j'ai réalisé que la question était C ++ et je n'ai pas pris la peine de chercher si C ++ avait fait la même faute de frappe n'importe où.
Steve Jessop
3

Échangez deux nombres en utilisant la troisième variable comme ceci,

int temp;
int a=10;
int b=20;
temp = a;
a = b;
b = temp;
printf ("Value of a", %a);
printf ("Value of b", %b);

Échange de deux nombres sans utiliser la troisième variable

int a = 10;
int b = 20;
a = a+b;
b = a-b;
a = a-b;
printf ("value of a=", %a);
printf ("value of b=", %b);
Ashwini
la source
2
#include<iostream.h>
#include<conio.h>
void main()
{
int a,b;
clrscr();
cout<<"\n==========Vikas==========";
cout<<"\n\nEnter the two no=:";
cin>>a>>b;
cout<<"\na"<<a<<"\nb"<<b;
a=a+b;
b=a-b;
a=a-b;

cout<<"\n\na="<<a<<"\nb="<<b;
getch();
}
vikas
la source
1
Après cout << "Enter the two no=:"je m'attendais à lirecout << "Now enter the two no in reverse order:"
user253751
Comme avec plusieurs autres réponses, cela a un comportement indéfini si a+bou a-bdéborde. De plus, void main()n'est pas valide et <conio.h>n'est pas standard.
Keith Thompson
2

Puisque la solution originale est:

temp = x; y = x; x = temp;

Vous pouvez en faire une doublure en utilisant:

temp = x; y = y + temp -(x=y);

Puis faites-en un one liner en utilisant:

x = x + y -(y=x);
user3258202
la source
1
Comportement indéfini. yest lu et écrit dans la même expression sans point de séquence intermédiaire.
Keith Thompson
1

Si vous modifiez un peu la question pour poser environ 2 registres d'assemblage au lieu de variables, vous pouvez également utiliser l' xchgopération comme une option et l'opération de pile comme une autre.

rkellerm
la source
1
De quelle xchgopération parlez-vous? La question ne spécifiait pas une architecture de processeur.
Keith Thompson
1

Considérez a=10, b=15:

Utilisation de l'addition et de la soustraction

a = a + b //a=25
b = a - b //b=10
a = a - b //a=15

Utilisation de la division et de la multiplication

a = a * b //a=150
b = a / b //b=10
a = a / b //a=15
Venkat
la source
1
A un comportement indéfini en cas de débordement.
Keith Thompson
1
En outre, en C ++, il peut avoir un comportement indésirable lorsque les valeurs ne sont pas du même type. Par exemple, a=10et b=1.5.
Matthew Cole
1
#include <iostream>
using namespace std;
int main(void)
{   
 int a,b;
 cout<<"Enter a integer" <<endl;
 cin>>a;
 cout<<"\n Enter b integer"<<endl;
 cin>>b;

  a = a^b;
  b = a^b;
  a = a^b;

  cout<<" a= "<<a <<"   b="<<b<<endl;
  return 0;
}

Mise à jour: En cela, nous prenons la saisie de deux entiers de l'utilisateur. Ensuite, nous utilisons l'opération XOR au niveau du bit pour les permuter.

Disons que nous avons deux entiers a=4et b=9puis:

a=a^b --> 13=4^9 
b=a^b --> 4=13^9 
a=a^b --> 9=13^9
Naeem Ul Hassan
la source
Veuillez ajouter une brève explication à votre réponse pour les futurs visiteurs.
Nikolay Mihaylov
1
En cela, nous prenons l'entrée de deux entiers de l'utilisateur. Ensuite, nous utilisons l'opération xor au niveau du bit pour les échanger. Disons que nous avons deux entiers a = 4 et b = 9 alors maintenant a = a ^ b -> 13 = 4 ^ 9 b = a ^ b -> 4 = 13 ^ 9 a = a ^ b -> 9 = 13 ^ 9
Naeem Ul Hassan
1

Voici une autre solution mais un seul risque.

code:

#include <iostream>
#include <conio.h>
void main()
{

int a =10 , b =45;
*(&a+1 ) = a;
a =b;
b =*(&a +1);
}

toute valeur à l'emplacement a + 1 sera remplacée.

DareDevil
la source
2
C'était une réponse utile, peut-être que la valeur a disparu.
Bibi Tahira
1
Plusieurs types de comportement indéfini. *(&a+1)pourrait bien être b. void main()est invalide. <conio.h>n'est pas standard (et vous ne l'utilisez même pas).
Keith Thompson
Le code a été testé avec d'autres paramètres de sortie, ce qui excluait, comme je l'ai mentionné, un risque. Le risque de mémoire surchargée .. C'est là .. Mais c'était un échange utile de deux variables sans implication de troisième.
DareDevil
Le pire, c'est que cela peut fonctionner à certains moments, donc vous ne réaliserez peut-être pas immédiatement qu'il est complètement cassé et qu'il échouera sous l'optimisation, d'autres compilateurs, etc.
avl_sweden
1

Bien sûr, la réponse C ++ devrait être std::swap.

Cependant, il n'y a pas non plus de troisième variable dans l'implémentation suivante de swap:

template <typename T>
void swap (T &a, T &b) {
    std::pair<T &, T &>(a, b) = std::make_pair(b, a);
}

Ou, en monoplace:

std::make_pair(std::ref(a), std::ref(b)) = std::make_pair(b, a);
jxh
la source
0
#include <stdio.h>

int main()
{
    int a, b;
    printf("Enter A :");
    scanf("%d",&a);
    printf("Enter B :");
    scanf("%d",&b);
    a ^= b;
    b ^= a;
    a ^= b;
    printf("\nValue of A=%d B=%d ",a,b);
    return 1;
}
Siddiqui
la source
0

c'est le bon algorithme d'échange XOR

void xorSwap (int* x, int* y) {
   if (x != y) { //ensure that memory locations are different
      if (*x != *y) { //ensure that values are different
         *x ^= *y;
         *y ^= *x;
         *x ^= *y;
      }
   }
}

vous devez vous assurer que les emplacements de mémoire sont différents et que les valeurs réelles sont différentes car A XOR A = 0

Gianluca Ghettini
la source
Vous n'avez pas à vous assurer que les valeurs sont différentes.
user253751
0

Vous pouvez faire ... de manière simple ... en une seule ligne Logic

#include <stdio.h>

int main()
{
    int a, b;
    printf("Enter A :");
    scanf("%d",&a);
    printf("Enter B :");
    scanf("%d",&b);
    int a = 1,b = 2;
    a=a^b^(b=a);
    printf("\nValue of A=%d B=%d ",a,b);

    return 1;
}

ou

#include <stdio.h>

int main()
{
    int a, b;
    printf("Enter A :");
    scanf("%d",&a);
    printf("Enter B :");
    scanf("%d",&b);
    int a = 1,b = 2;
    a=a+b-(b=a);
    printf("\nValue of A=%d B=%d ",a,b);

    return 1;
}
MOHAMMAD S HUSSAIN
la source
1
Comportement indéfini. Dans les deux versions, best à la fois lu et modifié dans la même expression, sans point de séquence intermédiaire.
Keith Thompson
0
public void swapnumber(int a,int b){
    a = a+b-(b=a);
    System.out.println("a = "+a +" b= "+b);
}
Ashish Bhavsar
la source
0

La meilleure réponse serait d'utiliser XOR et de l'utiliser en une seule ligne serait cool.

    (x ^= y), (y ^= x), (x ^= y);

x, y sont des variables et la virgule entre elles introduit les points de séquence afin qu'elle ne devienne pas dépendante du compilateur. À votre santé!

Ankit Sharma
la source
0

Voyons un exemple c simple pour échanger deux nombres sans utiliser la troisième variable.

programme 1:

#include<stdio.h>
#include<conio.h>
main()
{
int a=10, b=20;
clrscr();
printf("Before swap a=%d b=%d",a,b);
a=a+b;//a=30 (10+20)
b=a-b;//b=10 (30-20)
a=a-b;//a=20 (30-10)
printf("\nAfter swap a=%d b=%d",a,b);
getch();
}

Production:

Avant échange a = 10 b = 20 Après échange a = 20 b = 10

Programme 2: Utilisation de * et /

Voyons un autre exemple pour échanger deux nombres en utilisant * et /.

#include<stdio.h>
#include<conio.h>
main()
{
int a=10, b=20;
clrscr();
printf("Before swap a=%d b=%d",a,b);
a=a*b;//a=200 (10*20)
b=a/b;//b=10 (200/20)
a=a/b;//a=20 (200/10)
printf("\nAfter swap a=%d b=%d",a,b);
getch();
}

Production:

Avant échange a = 10 b = 20 Après échange a = 20 b = 10

Programme 3: Utilisation de l'opérateur XOR bit à bit:

L'opérateur XOR au niveau du bit peut être utilisé pour permuter deux variables. Le XOR de deux nombres x et y renvoie un nombre dont tous les bits valent 1 partout où les bits de x et y diffèrent. Par exemple, XOR de 10 (en binaire 1010) et 5 (en binaire 0101) est 1111 et XOR de 7 (0111) et 5 (0101) est (0010).

#include <stdio.h>
int main()
{
 int x = 10, y = 5;
 // Code to swap 'x' (1010) and 'y' (0101)
 x = x ^ y;  // x now becomes 15 (1111)
 y = x ^ y;  // y becomes 10 (1010)
 x = x ^ y;  // x becomes 5 (0101)
 printf("After Swapping: x = %d, y = %d", x, y);
 return 0;

Production:

Après échange: x = 5, y = 10

Programme 4:

Personne n'a encore suggéré d'utiliser std :: swap.

std::swap(a, b);

Je n'utilise aucune variable temporaire et en fonction du type de a et b, l'implémentation peut avoir une spécialisation qui ne l'est pas non plus. L'implémentation doit être écrite en sachant si une «astuce» est appropriée ou non.

Problèmes avec les méthodes ci-dessus:

1) L'approche basée sur la multiplication et la division ne fonctionne pas si l'un des nombres est 0 car le produit devient 0 quel que soit l'autre nombre.

2) Les deux solutions arithmétiques peuvent provoquer un débordement arithmétique. Si x et y sont trop grands, l'addition et la multiplication peuvent sortir de l'intervalle entier.

3) Lorsque nous utilisons des pointeurs vers une variable et faisons un échange de fonction, toutes les méthodes ci-dessus échouent lorsque les deux pointeurs pointent vers la même variable. Voyons ce qui se passera dans ce cas si les deux pointent vers la même variable.

// Méthode basée sur XOR au niveau du bit

x = x ^ x; // x becomes 0
x = x ^ x; // x remains 0
x = x ^ x; // x remains 0

// Méthode basée sur l'arithmétique

x = x + x; // x becomes 2x
x = x  x; // x becomes 0
x = x  x; // x remains 0

Voyons le programme suivant.

#include <stdio.h>
void swap(int *xp, int *yp)
{
    *xp = *xp ^ *yp;
    *yp = *xp ^ *yp;
    *xp = *xp ^ *yp;
}

int main()
{
  int x = 10;
  swap(&x, &x);
  printf("After swap(&x, &x): x = %d", x);
  return 0;
}

Sortie :

Après échange (& x, & x): x = 0

L'échange d'une variable avec elle-même peut être nécessaire dans de nombreux algorithmes standard. Par exemple, voyez cette implémentation de QuickSort où nous pouvons échanger une variable avec elle-même. Le problème ci-dessus peut être évité en mettant une condition avant l'échange.

#include <stdio.h>
void swap(int *xp, int *yp)
{
    if (xp == yp) // Check if the two addresses are same
      return;
    *xp = *xp + *yp;
    *yp = *xp - *yp;
    *xp = *xp - *yp;
}
int main()
{
  int x = 10;
  swap(&x, &x);
  printf("After swap(&x, &x): x = %d", x);
  return 0;
}

Sortie :

Après échange (& x, & x): x = 10

shobhit2905
la source
0

Peut-être hors sujet, mais si vous savez ce que vous échangez une seule variable entre deux valeurs différentes, vous pourrez peut-être faire de la logique de tableau. Chaque fois que cette ligne de code est exécutée, elle permute la valeur entre 1 et 2.

n = [2, 1][n - 1]
émouvant
la source
0

Vous pourriez faire:

std::tie(x, y) = std::make_pair(y, x);

Ou utilisez make_tuple lors de l'échange de plus de deux variables:

std::tie(x, y, z) = std::make_tuple(y, z, x);

Mais je ne suis pas sûr si std :: tie utilise en interne une variable temporaire ou non!

pooya13
la source
0

En javascript:

function swapInPlace(obj) {
    obj.x ^= obj.y
    obj.y ^= obj.x
    obj.x ^= obj.y
}

function swap(obj) {
    let temp = obj.x
    obj.x = obj.y
    obj.y = temp
}

Soyez conscient du temps d'exécution des deux options.

En exécutant ce code, je l'ai mesuré.

console.time('swapInPlace')
swapInPlace({x:1, y:2})
console.timeEnd('swapInPlace') // swapInPlace: 0.056884765625ms

console.time('swap')
swap({x:3, y:6})
console.timeEnd('swap')        // swap: 0.01416015625ms

Comme vous pouvez le voir (et comme beaucoup l'ont dit), swap in place (xor) prend beaucoup de temps que l'autre option utilisant la variable temp.

ofir_aghai
la source
0

Il manque à R une affectation concurrente proposée par Edsger W.Dijkstra dans A Discipline of Programming , 1976, ch.4, p.29. Cela permettrait une solution élégante:

a, b    <- b, a         # swap
a, b, c <- c, a, b      # rotate right
user3604103
la source
-1
a = a + b - (b=a);

C'est très simple, mais cela peut soulever un avertissement.

Alsimoneau
la source
5
L'avertissement étant que ça ne marche pas? Nous ne savons pas si elle b=aest effectuée avant ou après a + b.
Bo Persson
-1

solution sur une seule ligne pour permuter deux valeurs en langage C.

a=(b=(a=a+b,a-b),a-b);
HARITUSH
la source
Comportement indéfini en cas de débordement.
Keith Thompson
-1
second_value -= first_value;
first_value +=  second_value;
second_value -= first_value;
second_value *= -1;
Zikria Qureshi
la source
Cela a un comportement non défini si l'une des opérations déborde ou sous-déborde. Il peut également perdre en précision si les objets sont à virgule flottante.
Keith Thompson