Tauschen Sie zwei Variablenwerte aus, ohne die dritte Variable zu verwenden

104

Eine der sehr kniffligen Fragen, die in einem Interview gestellt wurden.

Tauschen Sie die Werte zweier Variablen wie a=10und aus b=15.

Um zwei Variablenwerte auszutauschen, benötigen wir im Allgemeinen die dritte Variable wie:

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

Jetzt ist die Anforderung, Werte von zwei Variablen zu tauschen, ohne die dritte Variable zu verwenden.

Muhammad Akhtar
quelle
76
Beeindruckend. Eine schlecht gewählte Interviewfrage IMHO. Dies ist eine Technik, die in der Praxis selten, wenn überhaupt, nützlich ist. Es besteht eine gute Chance, dass dies nur den Optimierer des Compilers verwirrt, was zu weniger effizientem Code führt als ein "temporärer Austausch". Ich kann mir keinen guten Grund vorstellen, eine solche Frage zu stellen, es sei denn, dieser Ort, an dem Sie ein Interview geführt haben, befasst sich mit sehr mathematischen Dingen (denken Sie an die Entwicklung von Verschlüsselungsalgorithmen oder dergleichen).
Dan Moulding
10
In der Tat sagt Ihnen diese Frage nichts anderes, als ob der Kandidat diesen speziellen Trick kennt, der im Produktionscode so gut wie nutzlos ist. Ich nehme an, Sie könnten gelegentlich auf einen Zauberer stoßen, der es im Handumdrehen herausfindet, aber solche Leute, die den Trick noch nicht kennen, sind wahrscheinlich ziemlich selten.
CEO
2
Vielleicht wollen sie Leute ausmerzen, die denken, solche Tricks zu kennen, macht einen guten Programmierer aus? Achten Sie beim Lesen des XOR-Tricks auch darauf, wann er fehlschlägt (was IMO ihn für das allgemeine Tauschen von Ganzzahlen so gut wie unbrauchbar macht).
UncleBens

Antworten:

155

Verwendung des xor-Swap-Algorithmus

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


Warum der Test?

Der Test soll sicherstellen, dass x und y unterschiedliche Speicherorte haben (und nicht unterschiedliche Werte). Dies liegt daran, dass (p xor p) = 0und wenn sowohl x als auch y denselben Speicherort teilen, wenn einer auf 0 gesetzt ist, beide auf 0 gesetzt sind. Wenn sowohl * x als auch * y 0 sind, sind alle anderen xor-Operationen an * x und * y gleich 0 (da sie gleich sind), was bedeutet, dass die Funktion sowohl * x als auch * y auf 0 setzt.

Wenn sie dieselben Werte, aber nicht denselben Speicherort haben, funktioniert alles wie erwartet

*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


Sollte dies verwendet werden?

Im Allgemeinen nein. Der Compiler optimiert die temporäre Variable und sollte, da das Austauschen ein gängiges Verfahren ist, den optimalen Maschinencode für Ihre Plattform ausgeben.

Nehmen Sie zum Beispiel dieses in C geschriebene Schnelltestprogramm.

#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;    
}

Kompiliert mit:

gcc -Os main.c -o swap

Die xor-Version dauert

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

Wo wie die Version mit der temporären Variablen nimmt:

real    0m0.543s
user    0m0.540s
sys  0m0.000s
Yacoby
quelle
1
Könnte es wert sein, das Warum des Tests zu erklären (dh, dass der dreifache xor-Ansatz schrecklich fehlschlägt, wenn x und y auf dasselbe Objekt verweisen).
dmckee --- Ex-Moderator Kätzchen
1
Ich weiß nicht, wie das so viele positive Stimmen bekommen hat, wenn der Code so kaputt ist. Beide Swaps im getesteten Codesegment sind völlig falsch. Schau genau hin.
SoapBox
@ SoapBox: Sehr guter Punkt! Der XOR-Tausch Nullen x & lässt y unberührt, und der temporäre Tausch lässt beide mit dem Wert x. Hoppla!
Drew Hall
4
@ SoapBox Guter Fang. Behoben und erneut getestet und ich bekomme keinen großen Unterschied in den Timings.
Yacoby
4
Der Fragesteller sagte zwei Variablen, nicht Ints. : P
Plumenator
92

Die allgemeine Form lautet:

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

Sie müssen jedoch möglicherweise auf Überläufe achten, und auch nicht alle Operationen haben eine Umkehrung, die für alle Werte, für die die Operation definiert ist, gut definiert ist. zB * und / arbeiten bis A oder B 0 ist

xor ist besonders erfreulich, da es für alle Ints definiert ist und seine eigene Umkehrung ist

jk.
quelle
XOR (X, X) == 0, also funktioniert xor für Ints AUSSER, wenn die beiden Werte, die ausgetauscht werden, gleich sind. Ich bin nicht der erste, der darauf hinweist, und zu viele haben es (hier und anderswo) gesagt, um jemanden für Kredite auszusuchen.
AlanK
84
a = a + b
b = a - b // b = a
a = a - b
Dor
quelle
16
Was ist, wenn es a+büberläuft?
Alok Singhal
2
@ Alok: Das wird nicht berücksichtigt, daher ist es unpraktisch :)
Dor
4
Wenn a und b sind die gleichen, grundlegenden, Größe Integer - Typen (wie int, unsigned short, ...), es funktioniert immer noch am Ende, selbst mit Überlauf, denn wenn a + b überläuft, dann a - b wird unterlaufen . Bei diesen grundlegenden Ganzzahltypen werden die Werte nur verschoben.
Patrick Johnmeyer
10
In C ist die Verwendung dieser unsignedOption für ganzzahlige Typen in Ordnung und funktioniert immer. Bei signierten Typen wird beim Überlauf ein undefiniertes Verhalten ausgelöst.
Jpalecek
1
@ Shahbaz: Auch wenn vorzeichenbehaftete Ganzzahlen im 2er-Komplement gespeichert sind , ist das Verhalten beim Überlauf immer noch undefiniert.
Keith Thompson
78

std::swapNoch hat niemand vorgeschlagen , zu verwenden.

std::swap(a, b);

Ich verwende keine temporären Variablen und je nach Art aund bImplementierung kann es zu einer Spekalisierung kommen, die dies auch nicht tut. Die Implementierung sollte so geschrieben werden, dass bekannt ist, ob ein „Trick“ angemessen ist oder nicht. Es macht keinen Sinn, zu raten.

Im Allgemeinen würde ich wahrscheinlich so etwas tun wollen, da dies für Klassentypen funktionieren würde, die es ADL ermöglichen, wenn möglich eine bessere Überlastung zu finden.

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

Natürlich könnte die Reaktion des Interviewers auf diese Antwort viel über die Vakanz aussagen.

CB Bailey
quelle
Natürlich verwendet Swap in C ++ 0x R-Wert-Referenzen, ist also noch besser!
jk.
16
Jeder möchte den glänzenden Xor oder einen anderen Trick, den er gelernt hat, mit verschiedenen Einschränkungen in Bezug auf die Verwendung vorführen, aber dies ist zweifellos die beste Antwort.
2
warum nicht std :: swap (a, b); ? Ich meine, warum die Verwendung?
Dinaiz
2
@Dinaiz ohne die std::benutzerdefinierten swapImplementierungen für benutzerdefinierte Typen kann ebenfalls aufgerufen werden (dies ist gemeint mit "es würde für Klassentypen funktionieren, die es ADL ermöglichen, wenn möglich eine bessere Überladung zu finden").
Kyle Strand
std::swapverwendet zusätzlichen temporären Speicher in seiner Implementierung nein? cplusplus.com/reference/utility/swap
Ninja
19

Wie bereits von manu bemerkt, ist der XOR-Algorithmus ein beliebter Algorithmus, der für alle ganzzahligen Werte funktioniert (einschließlich Zeiger, mit etwas Glück und Casting). Der Vollständigkeit halber möchte ich einen weiteren weniger leistungsfähigen Algorithmus mit Addition / Subtraktion erwähnen:

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

Hier muss man auf Über- / Unterläufe achten, sonst funktioniert es genauso gut. Sie können dies sogar bei Floats / Doubles versuchen, falls XOR auf diesen nicht zulässig ist.

Vilx-
quelle
" alle ganzzahligen Werte (die dann Zeiger enthalten) " - Was? Nein, Zeiger sind keine Ganzzahlen, und Sie können keine Zeigerwerte xor. Sie können auch keine Gleitkommawerte xor. Die Additions- / Subtraktionsmethode weist jedoch ein undefiniertes Verhalten (für vorzeichenbehaftete oder Gleitkommatypen) bei Überlauf oder Unterlauf auf, kann bei Gleitkommazahlen an Genauigkeit verlieren und kann nicht auf Zeiger oder andere nicht numerische Typen angewendet werden.
Keith Thompson
@KeithThompson - OK, der Genauigkeitsverlust für Gleitkommazahlen ist wahr, kann jedoch je nach den Umständen akzeptabel sein. Was die Zeiger betrifft - nun, ich habe noch nie von einem Compiler / einer Plattform gehört, bei der Zeiger nicht frei in ganze Zahlen und wieder zurück umgewandelt werden können (wobei natürlich darauf geachtet wird, eine ganze Zahl mit der richtigen Größe zu wählen). Aber dann bin ich kein C / C ++ - Experte. Ich weiß, dass es gegen den Standard verstößt, aber ich hatte den Eindruck, dass dieses Verhalten über ... alles hinweg ziemlich konsistent ist.
Vilx
1
@ Vilx-: Warum sollte ein Genauigkeitsverlust akzeptabel sein, wenn es so einfach ist, ihn durch die Verwendung einer temporären Variablen zu vermeiden - oder std::swap()? Natürlich können Sie Zeiger in Ganzzahlen und wieder zurück konvertieren (vorausgesetzt, es gibt einen ausreichend großen Ganzzahltyp, der nicht garantiert ist), aber das haben Sie nicht vorgeschlagen. Sie impliziert , dass die Zeiger sind ganze Zahlen, nicht , dass sie auf ganze Zahlen umgewandelt werden können. Ja, die akzeptierte Antwort funktioniert nicht für Zeiger. Charles Bailey Antwort mit std::swapwirklich die einzig richtige.
Keith Thompson
1
Zuallererst war die Frage "wie man ohne Verwendung einer dritten Variablen tauscht" und der Grund dafür war "eine Interviewfrage". Ich habe nur eine andere mögliche Antwort gegeben. Zweitens, OK, ich entschuldige mich dafür, dass Zeiger ganze Zahlen sind. Ich habe die Antwort aktualisiert, um hoffentlich expliziter und korrekter zu sein. Bitte korrigieren Sie mich, wenn ich immer noch falsch liege (oder aktualisieren Sie die Antwort selbst). Drittens habe ich den Teil über die akzeptierte Antwort gelöscht. Es werden nirgendwo Zeiger-zu-Ganzzahl-Casts verwendet und es funktioniert korrekt (soweit ich das verstehe).
Vilx
@KeithThompson: Die Frage könnte dahingehend geändert werden, wie std::swapsie ohne Verwendung einer dritten Variablen implementiert werden kann.
jxh
10

Dumme Fragen verdienen angemessene Antworten:

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

Die einzig gute Verwendung des registerSchlüsselworts.

MSalters
quelle
1
Ist ein mit Speicherklassenregister deklariertes Objekt keine "Variable"? Ich bin auch nicht davon überzeugt, dass dies eine gute Verwendung des Registers ist, denn wenn Ihr Compiler dies nicht bereits optimieren kann, sollten Sie entweder den Müll akzeptieren, den Sie bekommen, oder die Assembly selbst schreiben ;-) Aber als Sie sagen, eine zwielichtige Frage verdient eine zwielichtige Antwort.
Steve Jessop
1
Nahezu alle modernen Compiler ignorieren die Registerspeicherklasse, da sie eine viel bessere Vorstellung davon haben, auf was häufig zugegriffen wird, als Sie.
CEO
6
Beachten Sie, dass diese Antwort für Interviews gedacht ist, nicht für Compiler. Es nutzt insbesondere die Tatsache aus, dass die Art von Interviewern, die diese Art von Frage stellen, C ++ nicht wirklich verstehen. Sie können diese Antwort also nicht ablehnen. (und es gibt keine Standardantwort; ISO C ++ spricht von Objekten, nicht von Variablen).
MSalters
Ah, ich verstehe dich. Ich habe im C-Standard nach einer Erwähnung der Variablen als Substantiv gesucht und nicht nur nach Nicht-Konstante. Ich habe eine in n1124 gefunden, im Abschnitt über for-Schleifen, die den Umfang der im Initialisierer deklarierten "Variablen" definieren. Dann wurde mir klar, dass die Frage C ++ war, und ich machte mir nicht die Mühe zu suchen, ob C ++ irgendwo den gleichen Tippfehler gemacht hatte.
Steve Jessop
3

Das Vertauschen von zwei Zahlen mit der dritten Variablen ist wie folgt:

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

Zwei Zahlen tauschen, ohne die dritte Variable zu verwenden

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
quelle
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
quelle
1
Nachdem cout << "Enter the two no=:"ich erwartet hatte zu lesencout << "Now enter the two no in reverse order:"
user253751
Wie bei mehreren anderen Antworten hat dies ein undefiniertes Verhalten, wenn a+boder a-büberläuft. Auch void main()ist ungültig und <conio.h>nicht Standard.
Keith Thompson
2

Da die ursprüngliche Lösung ist:

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

Sie können daraus einen Zweiliner machen, indem Sie Folgendes verwenden:

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

Machen Sie es dann zu einem Einzeiler, indem Sie Folgendes verwenden:

x = x + y -(y=x);
user3258202
quelle
1
Undefiniertes Verhalten. ywird im gleichen Ausdruck ohne dazwischenliegenden Sequenzpunkt gelesen und geschrieben.
Keith Thompson
1

Wenn Sie die Frage nach 2 Assembly-Registern anstelle von Variablen ein wenig ändern, können Sie auch die xchgOperation als eine Option und die Stack-Operation als eine andere verwenden.

rkellerm
quelle
1
Auf welche xchgOperation beziehen Sie sich? In der Frage wurde keine CPU-Architektur angegeben.
Keith Thompson
1

Betrachten Sie a=10, b=15:

Addition und Subtraktion verwenden

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

Division und Multiplikation verwenden

a = a * b //a=150
b = a / b //b=10
a = a / b //a=15
Venkat
quelle
1
Hat undefiniertes Verhalten beim Überlauf.
Keith Thompson
1
In C ++ kann es auch zu unerwünschtem Verhalten kommen, wenn die Werte nicht vom gleichen Typ sind. Zum Beispiel a=10und 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;
}

Update: Hier nehmen wir zwei Ganzzahlen vom Benutzer ein. Dann verwenden wir die bitweise XOR- Operation, um sie auszutauschen.

Sagen wir zwei ganzen Zahlen haben a=4und b=9dann:

a=a^b --> 13=4^9 
b=a^b --> 4=13^9 
a=a^b --> 9=13^9
Naeem Ul Hassan
quelle
Bitte fügen Sie Ihrer Antwort für zukünftige Besucher eine kurze Erklärung hinzu.
Nikolay Mihaylov
1
Dabei nehmen wir zwei Ganzzahlen vom Benutzer ein. Dann verwenden wir die bitweise xoder Operation zwei tauschen sie aus. Nehmen wir an, wir haben zwei Interger a = 4 und b = 9, dann ist jetzt a = a ^ b -> 13 = 4 ^ 9 b = a ^ b -> 4 = 13 ^ 9 a = a ^ b -> 9 = 13 ^ 9
Naeem Ul Hassan
1

Hier ist eine weitere Lösung, aber ein einziges Risiko.

Code:

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

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

Jeder Wert an Position a + 1 wird überschrieben.

Draufgänger
quelle
2
Es war eine nützliche Antwort, vielleicht verschwand der Wert.
Bibi Tahira
1
Verschiedene Arten von undefiniertem Verhalten. *(&a+1)könnte gut sein b. void main()ist ungültig. <conio.h>ist nicht Standard (und Sie verwenden es nicht einmal).
Keith Thompson
Der Code wurde mit anderen Ausgabeparametern getestet, die, wie ich bereits erwähnt habe, ein Risiko ausschlossen. Das Risiko, dass der Speicher überschrieben wird. Das ist da. Aber es war nützlich, zwei Variablen ohne Beteiligung der dritten zu tauschen.
DareDevil
Das Schlimmste ist, dass es tatsächlich einige Male funktioniert, so dass Sie möglicherweise nicht sofort feststellen, dass es vollständig defekt ist und unter Optimierung, anderen Compilern usw.
fehlschlägt
1

Natürlich sollte die C ++ - Antwort lauten std::swap.

Es gibt jedoch auch keine dritte Variable in der folgenden Implementierung von swap:

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

Oder als Einzeiler:

std::make_pair(std::ref(a), std::ref(b)) = std::make_pair(b, a);
jxh
quelle
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
quelle
0

Das ist der richtige XOR-Swap-Algorithmus

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;
      }
   }
}

Sie müssen sicherstellen, dass die Speicherorte unterschiedlich sind und dass die tatsächlichen Werte unterschiedlich sind, da A XOR A = 0 ist

Gianluca Ghettini
quelle
Sie müssen nicht sicherstellen, dass die Werte unterschiedlich sind.
user253751
0

Sie können ... auf einfache Weise ... innerhalb einer Zeile Logik

#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;
}

oder

#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
quelle
1
Undefiniertes Verhalten. Wird in beiden Versionen binnerhalb desselben Ausdrucks ohne dazwischenliegenden Sequenzpunkt gelesen und geändert.
Keith Thompson
0
public void swapnumber(int a,int b){
    a = a+b-(b=a);
    System.out.println("a = "+a +" b= "+b);
}
Ashish Bhavsar
quelle
0

Die beste Antwort wäre, XOR zu verwenden und es in einer Zeile zu verwenden, wäre cool.

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

x, y sind Variablen und das Komma zwischen ihnen führt die Sequenzpunkte ein, damit sie nicht vom Compiler abhängig werden. Prost!

Ankit Sharma
quelle
0

Sehen wir uns ein einfaches c-Beispiel an, um zwei Zahlen ohne Verwendung der dritten Variablen auszutauschen.

Programm 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();
}

Ausgabe:

Vor dem Tausch a = 10 b = 20 Nach dem Tausch a = 20 b = 10

Programm 2: Verwenden von * und /

Sehen wir uns ein weiteres Beispiel an, um zwei Zahlen mit * und / auszutauschen.

#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();
}

Ausgabe:

Vor dem Tausch a = 10 b = 20 Nach dem Tausch a = 20 b = 10

Programm 3: Verwendung des bitweisen XOR-Operators:

Mit dem bitweisen XOR-Operator können zwei Variablen ausgetauscht werden. Das XOR aus zwei Zahlen x und y gibt eine Zahl zurück, die alle Bits als 1 hat, wo immer sich die Bits von x und y unterscheiden. Zum Beispiel ist XOR von 10 (In Binary 1010) und 5 (In Binary 0101) 1111 und XOR von 7 (0111) und 5 (0101) ist (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;

Ausgabe:

Nach dem Tauschen: x = 5, y = 10

Programm 4:

Bisher hat noch niemand vorgeschlagen, std :: swap zu verwenden.

std::swap(a, b);

Ich verwende keine temporären Variablen und je nach Typ von a und b hat die Implementierung möglicherweise eine Spezialisierung, die dies auch nicht tut. Die Implementierung sollte so geschrieben werden, dass bekannt ist, ob ein „Trick“ angemessen ist oder nicht.

Probleme mit den oben genannten Methoden:

1) Der auf Multiplikation und Division basierende Ansatz funktioniert nicht, wenn eine der Zahlen 0 ist, da das Produkt unabhängig von der anderen Zahl 0 wird.

2) Beide arithmetischen Lösungen können einen arithmetischen Überlauf verursachen. Wenn x und y zu groß sind, können Addition und Multiplikation außerhalb des ganzzahligen Bereichs liegen.

3) Wenn wir Zeiger auf eine Variable verwenden und einen Funktionsaustausch durchführen, schlagen alle oben genannten Methoden fehl, wenn beide Zeiger auf dieselbe Variable zeigen. Lassen Sie uns einen Blick darauf werfen, was in diesem Fall passieren wird, wenn beide auf dieselbe Variable zeigen.

// Bitweise XOR-basierte Methode

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

// Arithmetikbasierte Methode

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

Lassen Sie uns das folgende Programm sehen.

#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;
}

Ausgabe :

Nach dem Tausch (& x, & x): x = 0

Das Austauschen einer Variablen mit sich selbst kann in vielen Standardalgorithmen erforderlich sein. Sehen Sie sich zum Beispiel diese Implementierung von QuickSort an, in der wir eine Variable mit sich selbst austauschen können. Das obige Problem kann vermieden werden, indem vor dem Austausch eine Bedingung gestellt wird.

#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;
}

Ausgabe :

Nach dem Tausch (& x, & x): x = 10

shobhit2905
quelle
0

Möglicherweise außerhalb des Themas, aber wenn Sie wissen, was Sie für eine einzelne Variable zwischen zwei verschiedenen Werten austauschen, können Sie möglicherweise Array-Logik ausführen. Jedes Mal, wenn diese Codezeile ausgeführt wird, wird der Wert zwischen 1 und 2 ausgetauscht.

n = [2, 1][n - 1]
sehr schön
quelle
0

Du könntest es tun:

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

Oder verwenden Sie make_tuple, wenn Sie mehr als zwei Variablen austauschen:

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

Ich bin mir aber nicht sicher, ob intern std :: tie eine temporäre Variable verwendet oder nicht!

pooya13
quelle
0

In 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
}

Beachten Sie die Ausführungszeit beider Optionen.

Durch Ausführen dieses Codes habe ich ihn gemessen.

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

Wie Sie sehen können (und wie viele sagten), dauert der Austausch an Ort und Stelle (xor) viel länger als die andere Option mit der temporären Variablen.

ofir_aghai
quelle
0

R fehlt eine gleichzeitige Zuordnung, wie von Edsger W. Dijkstra in A Discipline of Programming , 1976, Kap. 4, S. 29 vorgeschlagen. Dies würde eine elegante Lösung ermöglichen:

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

Es ist sehr einfach, aber es kann eine Warnung auslösen.

alsimoneau
quelle
5
Die Warnung ist, dass es nicht funktioniert? Wir wissen nicht, ob b=avorher oder nachher durchgeführt wird a + b.
Bo Persson
-1

Einzeilige Lösung zum Vertauschen von zwei Werten in der Sprache c.

a=(b=(a=a+b,a-b),a-b);
HARITUSH
quelle
Undefiniertes Verhalten beim Überlauf.
Keith Thompson
-1
second_value -= first_value;
first_value +=  second_value;
second_value -= first_value;
second_value *= -1;
Zikria Qureshi
quelle
Dies hat ein undefiniertes Verhalten, wenn einer der Vorgänge über- oder unterläuft. Es kann auch an Genauigkeit verlieren, wenn die Objekte Gleitkommazahlen sind.
Keith Thompson