Üçüncü değişkeni kullanmadan iki değişken değeri değiştirme


104

Bir röportajda sorulan çok zor sorulardan biri.

Gibi iki değişkenin değerlerini karşılıklı a=10ve b=15.

Genellikle iki değişken değerini takas etmek için 3. değişkene ihtiyacımız var:

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

Şimdi şart, 3. değişkeni kullanmadan iki değişkenin değerlerini değiştirmektir.


76
Vay. Kötü seçilmiş bir röportaj sorusu IMHO. Bu, pratikte nadiren yararlı olan bir tekniktir. Yalnızca derleyicinin optimize edicisinin kafasını karıştırması ve "geçici takas" dan daha az verimli kodla sonuçlanması için iyi bir şans var. Röportaj yaptığınız yer çok matematik ağırlıklı işlere karışmadıysa (düşünün: şifreleme algoritması geliştirme veya benzeri) Böyle bir soru sormak için iyi bir neden düşünemiyorum.
Dan Molding

10
Doğrusu, bu soru size adayın üretim kodunda oldukça yararsız olan bu özel numarayı bilip bilmediğinden başka bir şey söylemiyor. Sanırım bunu anında çözen bir sihirbazla karşılaşabilirsiniz, ancak bunun gibi hileyi bilmeyen insanlar muhtemelen oldukça nadirdir.
CEO

2
Belki de bu tür hileleri bilmenin iyi programcı yapan şey olduğunu düşünen insanları ayıklamak istiyorlar mı? Ayrıca, xor-trick'i okurken ne zaman başarısız olacağına da dikkat edin (ki bu IMO, genel amaçlı tamsayı takas için neredeyse tamamen yararsız hale getirir).
UncleBens

Yanıtlar:


155

Xor takas algoritmasını kullanma

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


Neden test?

Test, x ve y'nin farklı bellek konumlarına sahip olmasını sağlamaktır (farklı değerler yerine). Bunun nedeni (p xor p) = 0ve eğer hem x hem de y aynı bellek konumunu paylaşıyorsa, biri 0 olarak ayarlandığında her ikisinin de 0'a ayarlanmasıdır. Hem * x hem de * y 0 olduğunda, * x ve * y üzerindeki diğer tüm xor işlemleri eşit olacaktır 0 (aynı olduklarından), bu, işlevin hem * x hem de * y'yi 0 olarak ayarlayacağı anlamına gelir.

Aynı değerlere sahipler ancak aynı bellek konumuna sahip değillerse, her şey beklendiği gibi çalışır

*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


Bu kullanılmalı mı?

Genel durumlarda hayır. Derleyici geçici değişkeni optimize edecek ve takasın yaygın bir prosedür olduğu göz önüne alındığında, platformunuz için optimum makine kodunu üretmesi gerekir.

Örneğin C ile yazılmış bu hızlı test programını ele alalım.

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

Kullanılarak derlendi:

gcc -Os main.c -o swap

Xor sürümü alır

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

Geçici değişkenli sürümün aldığı yer:

real    0m0.543s
user    0m0.540s
sys  0m0.000s

1
Testin nedenini açıklamaya değer olabilir (yani, x ve y aynı nesneye atıfta bulunursa üçlü xor yaklaşımının korkunç bir şekilde başarısız olduğu).
dmckee --- eski moderatör kedi

1
Kod bu kadar bozukken bunun nasıl bu kadar çok olumlu oy aldığını bilmiyorum. Test edilen kod segmentindeki her iki takas da tamamen yanlış. Yakından bak.
SoapBox

@SoapBox: Çok iyi bir nokta! XOR takas sıfırları x &, y'ye dokunulmaz ve geçici takas, her ikisini de x değeriyle bırakır. Hata!
Drew Salonu

4
@SoapBox İyi yakaladı. Düzeltildi ve yeniden test edildi ve zamanlamalarda büyük bir fark görmüyorum.
Yacoby

4
Soru soran kişi iki değişken dedi, tam değil. : P
Plumenator

93

genel biçim:

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

ancak, potansiyel olarak taşmalara dikkat etmeniz gerekir ve ayrıca tüm işlemlerin, işlemin tanımlandığı tüm değerler için iyi tanımlanmış bir tersi yoktur. örneğin * ve / A veya B 0 olana kadar çalış

xor, tüm ints için tanımlandığı ve kendi tersi olduğu için özellikle sevindiricidir


XOR (X, X) == 0, dolayısıyla xor, takas edilen iki değer eşit olduğunda HARİCİ tamsayılar için çalışır. Buna ilk işaret eden ben değilim ve pek çok kişi bunu (burada ve başka yerlerde) kimseyi kredi için ayırmak için söyledi.
AlanK

85
a = a + b
b = a - b // b = a
a = a - b

16
Ya a+btaşarsa?
Alok Singhal

2
@Alok: Bu dikkate alınmaz, bu yüzden pratik değil :)
Dor

4
A ve b aynı, temel, boyutlu tamsayı türlerindeyse (gibi int,, unsigned short...), yine de sonunda taşma durumunda bile çalışır, çünkü a + b taşarsa, o zaman a - b aşağı taşar. Bu temel tamsayı türlerinde, değerler yalnızca devredilir.
Patrick Johnmeyer

11
C'de, unsignedtamsayı türlerinde bunu kullanmak tamamdır ve her zaman çalışır. İşaretli türlerde, taşmada tanımsız davranışı çağırır.
jpalecek

2
@Shahbaz: işaretlenmiş tam bile saklanan 2's-tamamlayıcı, taşma üzerindeki davranış hala tanımlanmamış.
Keith Thompson

79

Henüz kimse kullanılmasını std::swapönermedi.

std::swap(a, b);

Ben geçici değişkenler kullanmak ve türüne bağlı olarak yok ave buygulanması ya değil bir specalization sahip olabilir. Uygulama, bir "hile" nin uygun olup olmadığı bilerek yazılmalıdır. İkinci tahminde bulunmanın bir anlamı yok.

Daha genel olarak, ADL'nin mümkünse daha iyi bir aşırı yükleme bulmasını sağlayan sınıf türleri için işe yarayacağı için muhtemelen böyle bir şey yapmak isterdim.

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

Tabii ki, görüşmecinin bu cevaba tepkisi, boşluk hakkında çok şey söyleyebilir.


tabii ki C ++ 0x swap rvalue referanslarını kullanacak, bu yüzden daha da iyi olacak!
jk.

16
Herkes parlak xor'u veya öğrendikleri diğer numaraları, nasıl kullanılacağına dair çeşitli uyarılarla göstermek ister, ancak bu şüphesiz en iyi cevaptır.

2
neden std :: swap (a, b); ? Demek istediğim neden kullanılıyor?
Dinaiz

2
@Dinaiz olmadan std::, kullanıcı swaptanımlı türler için kullanıcı tanımlı uygulamalar da çağrılabilir (bu, "ADL'nin mümkünse daha iyi bir aşırı yükleme bulmasını sağlayan sınıf türleri için çalışacaktır" ile kastedilmektedir).
Kyle Strand

std::swapuygulamasında ek geçici bellek kullanır hayır? cplusplus.com/reference/utility/swap
Ninja

19

Manu tarafından daha önce belirtildiği gibi, XOR algoritması, tüm tamsayı değerleri için çalışan popüler bir algoritmadır (daha sonra, biraz şans ve döküm ile işaretçiler içerir). Tamlık adına toplama / çıkarma ile daha az güçlü başka bir algoritmadan bahsetmek istiyorum:

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

Burada taşmalara / yetersizliklere karşı dikkatli olmalısınız, ancak aksi takdirde o kadar iyi çalışır. XOR'a bunlarda izin verilmemesi durumunda, bunu float / double üzerinde deneyebilirsiniz.


" tüm tam sayı değerleri (o zaman işaretçiler içerir) " - Ne? Hayır, işaretçiler tamsayı değildir ve x veya işaretçi değerleri yapamazsınız. Ayrıca kayan noktalı değerleri xorayamazsınız. Ancak toplama / çıkarma yönteminin taşma veya yetersizlik durumunda tanımsız davranışı vardır (işaretli veya kayan nokta türleri için), kayan nokta için hassasiyet kaybedebilir ve işaretçiler veya diğer sayısal olmayan türlere uygulanamaz.
Keith Thompson

@KeithThompson - Tamam, kayan noktalar için hassasiyet kaybı doğru, ancak koşullara bağlı olarak kabul edilebilir. İşaretçilere gelince - peki, işaretçilerin tam sayılara serbestçe ve tekrar geri döndürülemeyeceği bir derleyici / platformu hiç duymadım (tabii ki doğru boyutta bir tamsayı seçmeye özen göstererek). Ama o zaman ben bir C / C ++ uzmanı değilim. Bunun standarda aykırı olduğunu biliyorum, ama bu davranışın her şeyde oldukça tutarlı olduğu izlenimine kapıldım.
Vilx

1
@ Vilx-: Geçici bir değişken kullanarak ondan kaçınmak bu kadar kolayken neden kesinlik kaybı kabul edilebilir std::swap()? Elbette, işaretçileri tam sayıya dönüştürebilir ve tekrar geri döndürebilirsiniz (yeterince büyük bir tam sayı türü olduğunu varsayarak, bu garanti edilmez), ancak önerdiğiniz bu değil; işaretçilerin tamsayılara dönüştürülebileceklerini değil , tam sayı olduğunu ima ettiniz . Evet, kabul edilen cevap işaretçiler için işe yaramayacaktır. Charles Bailey'nin cevabını kullanmak std::swapgerçekten tek doğru olanıdır.
Keith Thompson

1
Öncelikle soru "üçüncü bir değişken kullanmadan nasıl değiş tokuş yapılacağı" idi ve bunun için gösterilen sebep "bir görüşme sorusu" idi. Olası bir cevap daha verdim. İkinci olarak, işaretçilerin tam sayı olduğunu ima ettiğim için özür dilerim. Cevabı umarım daha açık ve doğru olacak şekilde güncelledim. Hala yanılıyorsam lütfen düzeltin (veya yanıtı kendiniz güncelleyin). Üçüncüsü, kabul edilen cevapla ilgili kısmı sildim. Hiçbir yerde işaretçi-tamsayı yayınlarını kullanmıyor ve doğru çalışıyor (anladığım kadarıyla).
Vilx

@KeithThompson: Soru, std::swapüçüncü bir değişken kullanılmadan nasıl uygulanabileceğiyle ilgili olacak şekilde değiştirilebilir .
jxh

10

Aptalca sorular uygun cevapları hak eder:

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

registerAnahtar kelimenin tek iyi kullanımı .


1
Depolama sınıfı kaydı ile bildirilen bir nesne "değişken" değil mi? Ayrıca bunun yazmaç için iyi bir kullanım olduğuna ikna olmadım, çünkü derleyiciniz bunu zaten optimize edemiyorsa, denemenin amacı ne olursa olsun, ya aldığınız çöpü kabul etmeli ya da derlemeyi kendiniz yazmalısınız ;-) Ama tehlikeli bir sorunun tehlikeli bir cevabı hak ettiğini söylüyorsunuz.
Steve Jessop

1
Hemen hemen tüm modern derleyiciler, sizden neye sık erişildiği konusunda çok daha iyi bir fikirleri olduğu için yazmaç depolama sınıfını görmezden gelir.
CEO

6
Bu cevabın derleyiciler için değil mülakatlar için tasarlandığını unutmayın. Özellikle bu tür soruları soran türden görüşmecilerin C ++ 'ı gerçekten anlamadıkları gerçeğinden yararlanır. Yani bu cevabı reddedemezler. (ve Standart bir cevap yoktur; ISO C ++ değişkenlerden değil nesnelerden bahseder).
MSalters

Ah, seni anlıyorum. Değişkenden bir isim olarak bahsetmek için C standardına bakıyordum ve sadece const olmayan anlamına gelmiyor. Başlatıcıda açıklanan "değişkenler" in kapsamını tanımlayan döngülerle ilgili bölümde n1124'te bir tane buldum. Sonra sorunun C ++ olduğunu fark ettim ve C ++ 'nın aynı yazım hatasını herhangi bir yerde yapıp yapmadığını görmek için arama yapmakla uğraşmadım.
Steve Jessop

3

Üçüncü değişkeni kullanarak iki sayıyı değiştirmek şöyle olur,

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

Üçüncü değişkeni kullanmadan iki sayının yerini değiştirme

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

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

1
cout << "Enter the two no=:"Okumayı bekledikten sonracout << "Now enter the two no in reverse order:"
user253751

Diğer birkaç cevapta olduğu gibi, bu, eğer a+bveya a-btaşarsa tanımsız bir davranışa sahiptir . Ayrıca void main()geçersizdir ve <conio.h>standart değildir.
Keith Thompson

2

Orijinal çözüm şu olduğundan:

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

Şunları kullanarak iki astar yapabilirsiniz:

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

Ardından şunları kullanarak tek astar yapın:

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

1
Tanımlanmamış davranış. yaraya giren sıra noktası olmadan aynı ifadede okunur ve yazılır.
Keith Thompson

1

Değişkenler yerine 2 montaj yazmacı hakkında sormak için soruyu biraz değiştirirseniz, xchgişlemi bir seçenek olarak ve yığın işlemini başka bir seçenek olarak da kullanabilirsiniz .


1
Hangi xchgoperasyondan bahsediyorsun? Soru, bir CPU mimarisini belirtmedi.
Keith Thompson

1

Düşünün a=10, b=15:

Toplama ve Çıkarmayı Kullanma

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

Bölmeyi ve çarpmayı kullanma

a = a * b //a=150
b = a / b //b=10
a = a / b //a=15

1
Taşma durumunda tanımsız davranışa sahiptir.
Keith Thompson

1
Ayrıca, C ++ 'da değerler aynı tip olmadığında istenmeyen davranışlara sahip olabilir. Örneğin a=10ve 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;
}

Güncelleme: Bunda kullanıcıdan iki tamsayı girdisi alıyoruz. Sonra bunları takas etmek için bitsel XOR işlemini kullanıyoruz .

İki tamsayılar olduğunu varsayalım a=4ve b=9daha sonra ve:

a=a^b --> 13=4^9 
b=a^b --> 4=13^9 
a=a^b --> 9=13^9

Lütfen gelecekteki ziyaretçiler için cevabınıza kısa bir açıklama ekleyin.
Nikolay Mihaylov

1
Bunda kullanıcıdan iki tamsayı girdisi alıyoruz. Sonra bitsel xor işlemini kullanıyoruz ikisini takas ediyoruz. Diyelim ki iki interlayıcımız var a = 4 ve b = 9 o zaman şimdi a = a ^ b -> 13 = 4 ^ 9 b = a ^ b -> 4 = 13 ^ 9 a = a ^ b -> 9 = 13 ^ 9
Naeem Ul Hassan

1

İşte bir çözüm daha ama tek bir risk.

kod:

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

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

a + 1 konumundaki herhangi bir değer geçersiz kılınır.


2
Faydalı bir cevaptı, belki de değeri kayboldu.
Bibi Tahira

1
Birkaç çeşit tanımsız davranış. *(&a+1)iyi olabilir b. void main()geçersizdir. <conio.h>standart değildir (ve onu kullanmıyorsunuz bile).
Keith Thompson

Kod, bir riskten bahsettiğim için hariç tutulan diğer çıktı parametreleriyle test edildi. Hafıza riski geçersiz kılındı ​​.. İşte orada .. Ama üçüncünün müdahalesi olmadan iki değişkeni değiştirmek faydalı oldu.
DareDevil

En kötü yanı, aslında bazı zamanlar çalışabilmesidir, bu nedenle tamamen bozuk olduğunu ve optimizasyon, diğer derleyiciler vb. Altında başarısız olacağını hemen anlayamayabilirsiniz
avl_sweden

1

Elbette, C ++ yanıtı olmalıdır std::swap.

Bununla birlikte, aşağıdaki uygulamada üçüncü bir değişken de yoktur swap:

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

Veya tek astar olarak:

std::make_pair(std::ref(a), std::ref(b)) = std::make_pair(b, a);

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

0

bu doğru XOR takas algoritmasıdır

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

bellek konumlarının farklı olduğundan ve ayrıca gerçek değerlerin farklı olduğundan emin olmalısınız çünkü A XOR A = 0


Değerlerin farklı olmasını sağlamak zorunda değilsiniz.
user253751

0

Yapabilirsin .... kolay bir şekilde ... tek satırda Mantık

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

veya

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

1
Tanımsız davranış. Her iki versiyonda da, baraya giren sıra noktası olmaksızın aynı ifade içinde hem okunur hem de değiştirilir.
Keith Thompson

0
public void swapnumber(int a,int b){
    a = a+b-(b=a);
    System.out.println("a = "+a +" b= "+b);
}

0

En iyi cevap XOR kullanmaktır ve onu tek satırda kullanmak harika olur.

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

x, y değişkenlerdir ve aralarındaki virgül sıra noktalarını tanıtarak derleyiciye bağımlı hale gelmez. Şerefe!


0

Üçüncü değişkeni kullanmadan iki sayıyı değiştirmek için basit bir c örneği görelim.

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

Çıktı:

Takas öncesi a = 10 b = 20 Takas sonrası a = 20 b = 10

Program 2: * ve / kullanma

* Ve / kullanarak iki sayıyı değiştirmek için başka bir örnek görelim.

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

Çıktı:

Takas öncesi a = 10 b = 20 Takas sonrası a = 20 b = 10

Program 3: Bitsel XOR operatörünün kullanılması:

Bitsel XOR operatörü iki değişkeni takas etmek için kullanılabilir. X ve y sayısının XOR'u, x ve y bitlerinin farklı olduğu yerlerde tüm bitleri 1 olan bir sayıyı döndürür. Örneğin, XOR of 10 (In Binary 1010) and 5 (In Binary 0101) is 1111 and XOR of 7 (0111) and 5 (0101) is (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;

Çıktı:

Değiştirmeden Sonra: x = 5, y = 10

Program 4:

Henüz kimse std :: swap kullanmayı önermedi.

std::swap(a, b);

Herhangi bir geçici değişken kullanmıyorum ve a ve b'nin türüne bağlı olarak uygulamanın da olmayan bir uzmanlığı olabilir. Uygulama, bir "hile" nin uygun olup olmadığı bilerek yazılmalıdır.

Yukarıdaki yöntemlerle ilgili sorunlar:

1) Çarpma ve bölme tabanlı yaklaşım, sayılardan biri 0 ise, ürün diğer sayıdan bağımsız olarak 0 olurken çalışmaz.

2) Her iki Aritmetik çözüm de aritmetik taşmaya neden olabilir. X ve y çok büyükse, toplama ve çarpma tamsayı aralığının dışına çıkabilir.

3) Bir değişkene işaretçi kullandığımızda ve bir işlev değişimi yaptığımızda, her iki işaretçi de aynı değişkeni gösterdiğinde yukarıdaki yöntemlerin tümü başarısız olur. Her ikisi de aynı değişkeni gösteriyorsa, bu durumda ne olacağına bir bakalım.

// Bitsel XOR tabanlı yöntem

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

// Aritmetik tabanlı yöntem

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

Aşağıdaki programı görelim.

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

Çıktı :

Değiştirmeden sonra (& x, & x): x = 0

Birçok standart algoritmada bir değişkeni kendisiyle değiştirmek gerekebilir. Örneğin, bir değişkeni kendisiyle değiştirebileceğimiz QuickSort uygulamasına bakın. Değişimden önce bir koşul koyarak yukarıdaki sorun önlenebilir.

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

Çıktı :

Değiştirmeden sonra (& x, & x): x = 10


0

Konu dışı olabilir, ancak tek bir değişkeni iki farklı değer arasında değiştirdiğinizi biliyorsanız, dizi mantığı yapabilirsiniz. Bu kod satırı her çalıştırıldığında, değeri 1 ile 2 arasında değiştirecektir.

n = [2, 1][n - 1]

0

Yapabilirsin:

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

Veya ikiden fazla değişkeni takas ederken make_tuple kullanın:

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

Ama dahili olarak std :: tie geçici bir değişken kullanıyor mu emin değilim!


0

JavaScript'te:

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
}

Her iki seçeneğin de uygulama süresine dikkat edin.

Bu kodu çalıştırarak ölçtüm.

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

Gördüğünüz gibi (ve birçoklarının söylediği gibi), yerinde takas (xor), temp değişkenini kullanan diğer seçenekten çok daha fazla zaman alır.


0

R , Edsger W. Dijkstra tarafından A Discipline of Programming , 1976, bölüm 4, s. 29'da önerildiği gibi eşzamanlı bir atama eksiktir . Bu, zarif bir çözüme izin verir:

a, b    <- b, a         # swap
a, b, c <- c, a, b      # rotate right

-1
a = a + b - (b=a);

Çok basit, ancak bir uyarı oluşturabilir.


5
İşe yaramadığı uyarısı? b=aÖnce mi sonra mı yapıldığını bilmiyoruz a + b.
Bo Persson

-1

c dilinde iki değeri takas etmek için tek satırlık çözüm.

a=(b=(a=a+b,a-b),a-b);

Taşma durumunda tanımlanmamış davranış.
Keith Thompson

-1
second_value -= first_value;
first_value +=  second_value;
second_value -= first_value;
second_value *= -1;

İşlemlerden herhangi biri taşarsa veya yetersiz kalırsa, bu tanımsız bir davranışa sahiptir. Nesneler kayan nokta ise hassasiyeti de kaybedebilir.
Keith Thompson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.