Eine der sehr kniffligen Fragen, die in einem Interview gestellt wurden.
Tauschen Sie die Werte zweier Variablen wie a=10
und 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.
Antworten:
Verwendung des xor-Swap-Algorithmus
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) = 0
und 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
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.
Kompiliert mit:
Die xor-Version dauert
Wo wie die Version mit der temporären Variablen nimmt:
quelle
Die allgemeine Form lautet:
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
quelle
quelle
a+b
überläuft?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.unsigned
Option für ganzzahlige Typen in Ordnung und funktioniert immer. Bei signierten Typen wird beim Überlauf ein undefiniertes Verhalten ausgelöst.std::swap
Noch hat niemand vorgeschlagen , zu verwenden.Ich verwende keine temporären Variablen und je nach Art
a
undb
Implementierung 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.
Natürlich könnte die Reaktion des Interviewers auf diese Antwort viel über die Vakanz aussagen.
quelle
std::
benutzerdefiniertenswap
Implementierungen 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").std::swap
verwendet zusätzlichen temporären Speicher in seiner Implementierung nein? cplusplus.com/reference/utility/swapWie 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:
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.
quelle
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 mitstd::swap
wirklich die einzig richtige.std::swap
sie ohne Verwendung einer dritten Variablen implementiert werden kann.Dumme Fragen verdienen angemessene Antworten:
Die einzig gute Verwendung des
register
Schlüsselworts.quelle
Das Vertauschen von zwei Zahlen mit der dritten Variablen ist wie folgt:
Zwei Zahlen tauschen, ohne die dritte Variable zu verwenden
quelle
quelle
cout << "Enter the two no=:"
ich erwartet hatte zu lesencout << "Now enter the two no in reverse order:"
a+b
odera-b
überläuft. Auchvoid main()
ist ungültig und<conio.h>
nicht Standard.Da die ursprüngliche Lösung ist:
Sie können daraus einen Zweiliner machen, indem Sie Folgendes verwenden:
Machen Sie es dann zu einem Einzeiler, indem Sie Folgendes verwenden:
quelle
y
wird im gleichen Ausdruck ohne dazwischenliegenden Sequenzpunkt gelesen und geschrieben.Wenn Sie die Frage nach 2 Assembly-Registern anstelle von Variablen ein wenig ändern, können Sie auch die
xchg
Operation als eine Option und die Stack-Operation als eine andere verwenden.quelle
xchg
Operation beziehen Sie sich? In der Frage wurde keine CPU-Architektur angegeben.Betrachten Sie
a=10
,b=15
:quelle
a=10
undb=1.5
.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=4
undb=9
dann:quelle
Hier ist eine weitere Lösung, aber ein einziges Risiko.
Code:
Jeder Wert an Position a + 1 wird überschrieben.
quelle
*(&a+1)
könnte gut seinb
.void main()
ist ungültig.<conio.h>
ist nicht Standard (und Sie verwenden es nicht einmal).Natürlich sollte die C ++ - Antwort lauten
std::swap
.Es gibt jedoch auch keine dritte Variable in der folgenden Implementierung von
swap
:Oder als Einzeiler:
quelle
quelle
Das ist der richtige XOR-Swap-Algorithmus
Sie müssen sicherstellen, dass die Speicherorte unterschiedlich sind und dass die tatsächlichen Werte unterschiedlich sind, da A XOR A = 0 ist
quelle
Sie können ... auf einfache Weise ... innerhalb einer Zeile Logik
oder
quelle
b
innerhalb desselben Ausdrucks ohne dazwischenliegenden Sequenzpunkt gelesen und geändert.quelle
Die beste Antwort wäre, XOR zu verwenden und es in einer Zeile zu verwenden, wäre cool.
x, y sind Variablen und das Komma zwischen ihnen führt die Sequenzpunkte ein, damit sie nicht vom Compiler abhängig werden. Prost!
quelle
Sehen wir uns ein einfaches c-Beispiel an, um zwei Zahlen ohne Verwendung der dritten Variablen auszutauschen.
Programm 1:
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.
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).
Ausgabe:
Nach dem Tauschen: x = 5, y = 10
Programm 4:
Bisher hat noch niemand vorgeschlagen, std :: swap zu verwenden.
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
// Arithmetikbasierte Methode
Lassen Sie uns das folgende Programm sehen.
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.
Ausgabe :
Nach dem Tausch (& x, & x): x = 10
quelle
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.
quelle
Du könntest es tun:
Oder verwenden Sie make_tuple, wenn Sie mehr als zwei Variablen austauschen:
Ich bin mir aber nicht sicher, ob intern std :: tie eine temporäre Variable verwendet oder nicht!
quelle
In Javascript:
Beachten Sie die Ausführungszeit beider Optionen.
Durch Ausführen dieses Codes habe ich ihn gemessen.
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.
quelle
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:
quelle
Es ist sehr einfach, aber es kann eine Warnung auslösen.
quelle
b=a
vorher oder nachher durchgeführt wirda + b
.Einzeilige Lösung zum Vertauschen von zwei Werten in der Sprache c.
quelle
quelle