Une des questions très délicates posées lors d'une interview.
Échangez les valeurs de deux variables comme a=10
et 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.
Réponses:
Utilisation de l' algorithme d'échange xor
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) = 0
et 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
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.
Compilé avec:
La version xor prend
Où prend la version avec la variable temporaire:
la source
la forme générale est:
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
la source
la source
a+b
débordements?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.unsigned
des types entiers est OK et fonctionne toujours. Sur les types signés, cela invoquerait un comportement indéfini en cas de débordement.Personne n'a encore suggéré d'utiliser
std::swap
.Je n'utilise aucune variable temporaire et selon le type de
a
etb
l'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.
Bien entendu, la réaction de l'intervieweur à cette réponse pourrait en dire long sur le poste vacant.
la source
std::
définiesswap
par 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»).std::swap
utilise de la mémoire temporaire supplémentaire dans son implémentation non? cplusplus.com/reference/utility/swapComme 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:
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.
la source
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 utilisantstd::swap
est vraiment la seule correcte.std::swap
mettre en œuvre sans utiliser une troisième variable.Les questions stupides méritent des réponses appropriées:
Le seul bon usage du
register
mot - clé.la source
Échangez deux nombres en utilisant la troisième variable comme ceci,
Échange de deux nombres sans utiliser la troisième variable
la source
la source
cout << "Enter the two no=:"
je m'attendais à lirecout << "Now enter the two no in reverse order:"
a+b
oua-b
déborde. De plus,void main()
n'est pas valide et<conio.h>
n'est pas standard.Puisque la solution originale est:
Vous pouvez en faire une doublure en utilisant:
Puis faites-en un one liner en utilisant:
la source
y
est lu et écrit dans la même expression sans point de séquence intermédiaire.Si vous modifiez un peu la question pour poser environ 2 registres d'assemblage au lieu de variables, vous pouvez également utiliser l'
xchg
opération comme une option et l'opération de pile comme une autre.la source
xchg
opération parlez-vous? La question ne spécifiait pas une architecture de processeur.Considérez
a=10
,b=15
:la source
a=10
etb=1.5
.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=4
etb=9
puis:la source
Voici une autre solution mais un seul risque.
code:
toute valeur à l'emplacement a + 1 sera remplacée.
la source
*(&a+1)
pourrait bien êtreb
.void main()
est invalide.<conio.h>
n'est pas standard (et vous ne l'utilisez même pas).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
:Ou, en monoplace:
la source
la source
c'est le bon algorithme d'échange XOR
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
la source
Vous pouvez faire ... de manière simple ... en une seule ligne Logic
ou
la source
b
est à la fois lu et modifié dans la même expression, sans point de séquence intermédiaire.la source
La meilleure réponse serait d'utiliser XOR et de l'utiliser en une seule ligne serait cool.
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é!
la source
Voyons un exemple c simple pour échanger deux nombres sans utiliser la troisième variable.
programme 1:
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 /.
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).
Production:
Après échange: x = 5, y = 10
Programme 4:
Personne n'a encore suggéré d'utiliser std :: swap.
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
// Méthode basée sur l'arithmétique
Voyons le programme suivant.
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.
Sortie :
Après échange (& x, & x): x = 10
la source
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.
la source
Vous pourriez faire:
Ou utilisez make_tuple lors de l'échange de plus de deux variables:
Mais je ne suis pas sûr si std :: tie utilise en interne une variable temporaire ou non!
la source
En javascript:
Soyez conscient du temps d'exécution des deux options.
En exécutant ce code, je l'ai mesuré.
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.
la source
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:
la source
C'est très simple, mais cela peut soulever un avertissement.
la source
b=a
est effectuée avant ou aprèsa + b
.solution sur une seule ligne pour permuter deux valeurs en langage C.
la source
la source