세 번째 변수를 사용하지 않고 두 변수 값 바꾸기


104

인터뷰에서 묻는 매우 까다로운 질문 중 하나입니다.

같은 두 변수의 값을 교환 a=10하고b=15 .

일반적으로 두 변수 값을 바꾸려면 다음과 같은 세 번째 변수가 필요합니다.

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

이제 요구 사항은 세 번째 변수를 사용하지 않고 두 변수의 값을 바꾸는 것입니다.


76
와. 잘못 선택한 인터뷰 질문 IMHO. 이것은 실제로 거의 유용하지 않은 기술입니다. 컴파일러의 옵티 마이저를 혼동하여 "임시 스왑"보다 효율적인 코드를 생성 할 가능성이 있습니다. 당신이 인터뷰를했던 이곳이 수학이 많은 일 (암호화 알고리즘 개발 등을 생각해보십시오)에 관여하지 않는 한 저는 그러한 질문을해야 할 좋은 이유를 상상할 수 없습니다.
Dan Molding

10
사실, 그 질문은 후보자가 프로덕션 코드에서 거의 쓸모없는이 특별한 트릭을 알고 있는지 여부 외에는 아무것도 알려주지 않습니다. 나는 당신이 그것을 즉시 알아내는 가끔 마법사를 만날 수 있다고 생각하지만, 그 속임수를 아직 모르는 사람들은 꽤 드뭅니다.
ceo

2
그런 속임수를 아는 것이 좋은 프로그래머가된다고 생각하는 사람들을 제거하고 싶을까요? 또한 xor-trick에 대해 읽을 때 실패 할 때주의를 기울이십시오 (IMO가 범용 정수 스와핑에 거의 완전히 쓸모 없게 만듭니다).
UncleBens

답변:


155

은 Using XOR 스왑 알고리즘을

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


왜 테스트입니까?

테스트는 x와 y가 다른 값이 아닌 다른 메모리 위치를 가지고 있는지 확인하는 것입니다. 이는 (p xor p) = 0x와 y가 동일한 메모리 위치를 공유하는 경우 하나가 0으로 설정되면 둘 다 0으로 설정되기 때문입니다. * x와 * y가 모두 0이면 * x 및 * y에 대한 다른 모든 xor 연산은 동일합니다. 0 (동일하기 때문에), 이는 함수가 * x와 * y를 모두 0으로 설정 함을 의미합니다.

값은 같지만 메모리 위치가 같지 않으면 모든 것이 예상대로 작동합니다.

*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


이것을 사용해야합니까?

일반적인 경우에는 그렇지 않습니다. 컴파일러는 임시 변수를 최적화하고 스와핑이 일반적인 절차라는 점을 고려할 때 플랫폼에 대한 최적의 기계 코드를 출력해야합니다.

예를 들어 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;    
}

다음을 사용하여 컴파일 :

gcc -Os main.c -o swap

xor 버전은

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

임시 변수가있는 버전은 다음과 같습니다.

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

1
테스트의 이유를 설명 할 가치가있을 수 있습니다 (즉, x와 y가 동일한 객체를 참조하면 트리플 xor 접근 방식이 끔찍하게 실패 함).
dmckee --- ex-moderator kitten

1
코드가 너무 손상되었을 때 이것이 어떻게 그렇게 많은 찬성표를 얻었는지 모르겠습니다. 테스트 된 코드 세그먼트의 두 스왑 모두 완전히 잘못되었습니다. 가까이 봐.
SoapBox

@SoapBox : 아주 좋은 지적입니다! XOR 스왑은 x를 0으로하고 y는 그대로두고 임시 스왑은 둘 다 x의 값으로 둡니다. 이런!
Drew Hall

4
@SoapBox 좋은 캐치. 수정되고 다시 테스트되었으며 타이밍에 큰 차이가 없습니다.
Yacoby 2010

4
질문자는 int가 아닌 두 개의 변수를 말했습니다. : P
Plumenator

93

일반적인 형식은 다음과 같습니다.

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

그러나 잠재적으로 오버플로를 조심해야하며 모든 작업에 작업이 정의 된 모든 값에 대해 잘 정의 된 역이있는 것은 아닙니다. 예 * 및 / A 또는 B가 0이 될 때까지 작동

xor는 모든 int에 대해 정의되고 자체 역이므로 특히 즐겁습니다.


XOR (X, X) == 0이므로 xor는 교환되는 두 값이 같을 때를 제외하고 int에 대해 작동합니다. 나는 이것을 처음으로 지적하는 것이 아니며 너무 많은 사람들이 신용을 위해 누군가를 뽑아내는 것을 (여기와 다른 곳에서) 말했습니다.
AlanK

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

16
만약에 a+b오버 플로우?
Alok Singhal

2
@Alok : 고려하지 않았으므로 비실용적입니다. :)
Dor

4
a와 b가 동일한 기본 크기의 정수 유형 (예 int: unsigned short,, ...) 인 경우, a + b가 오버플로되면 a-b가 언더 플로되기 때문에 오버플로가 있더라도 결국 작동합니다. 이러한 기본 정수 유형을 사용하면 값이 롤오버됩니다.
Patrick Johnmeyer 2010

10
C에서는 unsigned정수 유형에 이것을 사용하는 것이 좋으며 항상 작동합니다. 서명 된 유형에서는 오버플로시 정의되지 않은 동작을 호출합니다.
jpalecek 2010

1
@Shahbaz : 부호있는 정수가 2의 보수 로 저장 되더라도 오버플로 동작은 여전히 ​​정의되지 않습니다.
Keith Thompson

79

std::swap아직 아무도 사용을 제안 하지 않았습니다.

std::swap(a, b);

나는 임시 변수를 사용하지 않으며 유형 ab구현 에 따라 어느 쪽도 아닌 specalization을 가질 수 있습니다. 구현은 '트릭'이 적절한 지 여부를 알고 작성되어야합니다. 두 번째 추측을 시도하는 것은 의미가 없습니다.

일반적으로 ADL이 가능한 한 더 나은 오버로드를 찾을 수 있도록하는 클래스 유형에 대해 작동하므로 이와 같은 작업을 수행하고 싶을 것입니다.

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

물론이 답변에 대한 면접관의 반응은 공석에 대해 많은 것을 말할 수 있습니다.


물론 C ++ 0x에서 스왑은 rvalue 참조를 사용하므로 더 좋을 것입니다!
jk.

16
모든 사람들은 사용 방법에 대한 다양한 경고와 함께 반짝이는 xor 또는 배운 다른 트릭을 과시하고 싶어하지만 이것이 틀림없이 최선의 답입니다.

2
왜 std :: swap (a, b); ? 왜 사용합니까?
Dinaiz

2
사용자 정의 유형에 대한 std::, 사용자 정의 swap구현이 없는 @Dinaiz 도 호출 할 수 있습니다 (이는 "가능한 경우 ADL이 더 나은 오버로드를 찾을 수 있도록하는 클래스 유형에 대해 작동합니다"라는 의미입니다).
Kyle Strand

std::swap구현에 추가 임시 메모리를 사용합니까? cplusplus.com/reference/utility/swap
Ninja

19

manu에서 이미 언급했듯이 XOR 알고리즘은 모든 정수 값에 대해 작동하는 인기있는 알고리즘입니다 (포인터 포함, 운과 캐스팅 포함). 완전성을 위해 더하기 / 빼기를 ​​사용하는 덜 강력한 또 다른 알고리즘을 언급하고 싶습니다.

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

여기서는 오버 플로우 / 언더 플로우에주의해야하지만 그렇지 않으면 잘 작동합니다. XOR이 허용되지 않는 경우 float / doubles에서 이것을 시도 할 수도 있습니다.


" 모든 정수 값 (포인터 포함) "-뭐? 아니요, 포인터는 정수가 아니므로 포인터 값을 xor 할 수 없습니다. 또한 부동 소수점 값을 xor 할 수 없습니다. 그러나 더하기 / 빼기 방법은 오버플로 또는 언더 플로에서 정의되지 않은 동작 (부호 또는 부동 소수점 유형의 경우)을 가지며 부동 소수점의 정밀도를 잃을 수 있으며 포인터 또는 기타 숫자가 아닌 유형에 적용 할 수 없습니다.
Keith Thompson

@KeithThompson-좋아, 부동 소수점에 대한 정밀도 손실은 사실이지만 상황에 따라 허용 될 수 있습니다. 포인터에 관해서는-포인터를 정수로 자유롭게 캐스트하고 다시 되돌릴 수없는 컴파일러 / 플랫폼에 대해 들어 본 적이 없습니다 (물론 올바른 크기의 정수를 선택하도록주의). 하지만 저는 C / C ++ 전문가가 아닙니다. 나는 그것이 표준에 위배된다는 것을 알고 있지만, 나는이 행동이 모든 것에서 꽤 일관 적이라는 인상을 받았습니다.
Vilx-

1
@ Vilx- : 임시 변수를 사용하여 쉽게 피할 수 있는데 정밀도 손실이 허용되는 이유는 무엇 std::swap()입니까? 물론 포인터를 정수 로 변환 했다가 다시 되돌릴 수 있습니다 (보장되지 않는 충분히 큰 정수 유형이 있다고 가정). 그러나 그것은 당신이 제안한 것이 아닙니다. 포인터 정수로 변환 될 수있는 것이 아니라 정수라 것을 암시했습니다 . 예, 수락 된 답변은 포인터에 대해 작동하지 않습니다. Charles Bailey의 대답 사용 std::swap은 실제로 유일한 정답입니다.
Keith Thompson

1
우선 질문은 "제 3 변수를 사용하지 않고 스왑하는 방법"이었고 그 이유는 "면접 질문"이었습니다. 나는 다른 가능한 대답을 주었다. 둘째, 좋습니다. 포인터가 정수라고 암시 한 것에 대해 사과드립니다. 나는 답변을 더 명확하고 정확하도록 업데이트했습니다. 내가 여전히 틀렸다면 저를 수정하십시오 (또는 직접 답변을 업데이트하십시오). 셋째, 수락 된 답변에 대한 부분을 삭제했습니다. 어디에서나 정수에 대한 포인터 캐스트를 사용하지 않으며 올바르게 작동합니다 (내가 이해하는 한).
Vilx-

@KeithThompson : std::swap세 번째 변수를 사용하지 않고 구현할 수있는 방법에 대한 질문을 수정할 수 있습니다.
jxh

10

어리석은 질문에는 적절한 답변이 필요합니다.

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

register키워드 의 유일한 좋은 사용 .


1
스토리지 클래스 레지스터로 선언 된 객체가 "변수"가 아닌가? 또한 이것이 레지스터의 좋은 사용이라고 확신하지 않습니다. 컴파일러가 이미 이것을 최적화 할 수 없다면 시도의 요점이 무엇인지, 당신이 얻는 쓰레기를 받아들이거나 어셈블리를 직접 작성해야하기 때문입니다 ;-) 그러나 엉뚱한 질문은 엉뚱한 대답이 필요하다고 말합니다.
Steve Jessop

1
거의 모든 최신 컴파일러는 레지스터 스토리지 클래스를 무시합니다. 사용자보다 자주 액세스하는 것에 대해 훨씬 더 잘 알고 있기 때문입니다.
ceo

6
이 답변은 컴파일러가 아닌 인터뷰를위한 것입니다. 특히 이런 종류의 질문을하는 면접관이 C ++를 실제로 이해하지 못한다는 사실을 이용합니다. 따라서 그들은이 대답을 거부 할 수 없습니다. (표준 답변은 없습니다. ISO C ++는 변수가 아닌 객체에 대해 이야기합니다).
MSalters

아, 알겠습니다. 나는 변수를 명사로 언급하기 위해 C 표준을 찾고 있었고 비 상수를 의미하는 것이 아닙니다. 이니셜 라이저에 선언 된 "변수"의 범위를 정의하는 for 루프 섹션에서 n1124에서 하나를 찾았습니다. 그런 다음 질문이 C ++라는 것을 깨달았고 C ++가 어디서나 동일한 오타를 만들 었는지 확인하기 위해 검색하지 않았습니다.
스티브 제솝

3

세 번째 변수를 사용하여 두 숫자를 바꾸는 것은 다음과 같습니다.

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

세 번째 변수를 사용하지 않고 두 숫자 바꾸기

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=:"내가 읽기를 기대했던 후cout << "Now enter the two no in reverse order:"
user253751

다른 여러 답변과 마찬가지로 a+b또는 a-b오버플로 가 정의되지 않은 동작이 있습니다 . 또한 void main()유효하지 않으며 <conio.h>표준이 아닙니다.
Keith Thompson

2

원래 솔루션은 다음과 같습니다.

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

다음을 사용하여 2 개의 라이너로 만들 수 있습니다.

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

그런 다음 다음을 사용하여 하나의 라이너로 만듭니다.

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

1
정의되지 않은 동작. y시퀀스 포인트없이 동일한 식으로 읽고 씁니다.
Keith Thompson

1

변수 대신 2 개의 어셈블리 레지스터에 대해 묻는 질문을 조금 변경하면 xchg작업을 하나의 옵션으로 사용하고 스택 작업을 다른 옵션으로 사용할 수 있습니다 .


1
어떤 xchg작업을 언급하고 있습니까? 질문은 CPU 아키텍처를 지정하지 않았습니다.
Keith Thompson

1

고려 a=10, b=15:

더하기와 빼기 사용

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

나누기와 곱하기 사용

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

1
오버플로시 정의되지 않은 동작이 있습니다.
Keith Thompson

1
또한 C ++에서는 값이 동일한 유형이 아닐 때 원하지 않는 동작이 발생할 수 있습니다. 예를 들어 a=10b=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;
}

업데이트 : 여기서는 사용자로부터 두 개의 정수를 입력합니다. 그런 다음 비트 XOR 연산을 사용하여 스왑합니다.

우리는 두 개의 정수가 있다고 가정 a=4하고 b=9다음과 :

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

향후 방문자를 위해 답변에 간단한 설명을 추가하십시오.
Nikolay Mihaylov

1
여기서는 사용자로부터 두 개의 정수를 입력합니다. 그런 다음 비트 xor 연산을 사용하여 두 개의 스왑을 수행합니다. 두 개의 정수 a = 4와 b = 9가 있다고 가정하면 이제 a = a ^ b-> 13 = 4 ^ 9 b = a ^ b-> 4 = 13 ^ 9 a = a ^ b-> 9 = 13 ^ 9
Naeem Ul Hassan

1

여기에 하나 이상의 솔루션이 있지만 단일 위험이 있습니다.

암호:

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

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

a + 1 위치의 모든 값이 무시됩니다.


2
유용한 답변이었고 아마도 가치가 사라 졌을 것입니다.
Bibi Tahira 2013 년

1
여러 종류의 정의되지 않은 동작. *(&a+1)아마도 b. void main()유효하지 않다. <conio.h>비표준입니다 (사용하지도 않습니다).
Keith Thompson

코드는 위험을 언급했듯이 제외 된 다른 출력 매개 변수로 테스트되었습니다. 기억이 무시되는 위험 .. 그게 다야 ..하지만 세 번째의 개입없이 두 변수를 교환하는 데 유용했습니다.
DareDevil

최악의 부분은 당신이 바로이 완전히 깨진 실현되지 않을 수도 등 최적화, 다른 컴파일러, 아래에 실패 그래서 실제로 몇 번을 작동 할 수 있다는 것입니다
avl_sweden

1

물론 C ++ 대답은 std::swap.

그러나 다음 구현에는 세 번째 변수도 없습니다 swap.

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

또는 한 줄로 :

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

이것이 올바른 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;
      }
   }
}

A XOR A = 0이기 때문에 메모리 위치가 다르고 실제 값이 다른지 확인해야합니다.


값이 다른지 확인할 필요가 없습니다.
user253751 2015-08-26

0

당신은 .... 쉽게 할 수 있습니다 ... 한 줄로 논리

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

또는

#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
정의되지 않은 동작. 두 버전에서 b모두 동일한 표현식 내에서 읽고 수정되며 중간 시퀀스 지점이 없습니다.
Keith Thompson

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

0

가장 좋은 대답은 XOR을 사용하는 것이고 한 줄로 사용하는 것이 멋질 것입니다.

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

x, y는 변수이고 그 사이의 쉼표는 시퀀스 포인트를 도입하므로 컴파일러에 종속되지 않습니다. 건배!


0

세 번째 변수를 사용하지 않고 두 숫자를 바꾸는 간단한 c 예제를 살펴 보겠습니다.

프로그램 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();
}

산출:

스왑 전 a = 10 b = 20 스왑 후 a = 20 b = 10

프로그램 2 : * 및 / 사용

* 및 /를 사용하여 두 숫자를 바꾸는 또 다른 예를 살펴 보겠습니다.

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

산출:

스왑 전 a = 10 b = 20 스왑 후 a = 20 b = 10

프로그램 3 : 비트 XOR 연산자 사용 :

비트 XOR 연산자를 사용하여 두 개의 변수를 바꿀 수 있습니다. 두 숫자 x와 y의 XOR은 x와 y의 비트가 다를 때마다 모든 비트가 1 인 숫자를 반환합니다. 예를 들어, 10 (이진 1010) 및 5 (이진 0101)의 XOR은 1111이고 7 (0111) 및 5 (0101)의 XOR은 (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;

산출:

스와핑 후 : x = 5, y = 10

프로그램 4 :

아무도 std :: swap 사용을 제안하지 않았습니다.

std::swap(a, b);

나는 임시 변수를 사용하지 않으며 a와 b의 유형에 따라 구현에 둘 중 하나가 아닌 전문화를 가질 수 있습니다. 구현은 '트릭'이 적절한 지 여부를 알고 작성되어야합니다.

위 방법의 문제점 :

1) 곱셈 및 나눗셈 기반 접근 방식은 숫자 중 하나가 0이면 다른 숫자에 관계없이 곱이 0이되므로 작동하지 않습니다.

2) 두 산술 솔루션 모두 산술 오버플로를 일으킬 수 있습니다. x와 y가 너무 크면 더하기와 곱하기가 정수 범위를 벗어날 수 있습니다.

3) 변수에 대한 포인터를 사용하고 함수 스왑을 만들 때 두 포인터가 동일한 변수를 가리킬 때 위의 모든 메서드가 실패합니다. 둘 다 동일한 변수를 가리키는 경우이 경우 어떤 일이 발생하는지 살펴 보겠습니다.

// 비트 XOR 기반 방법

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

// 산술 기반 방법

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

다음 프로그램을 보겠습니다.

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

산출 :

스왑 후 (& x, & x) : x = 0

많은 표준 알고리즘에서 변수를 자체로 교체해야 할 수 있습니다. 예를 들어,이 QuickSort 구현을 참조하십시오. 여기서 변수를 자신과 바꿀 수 있습니다. 위의 문제는 스와핑 전에 조건을두면 피할 수 있습니다.

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

출력 :

스왑 후 (& x, & x) : x = 10


0

주제에서 벗어난 것일 수도 있지만 두 개의 다른 값 사이에서 단일 변수를 교환하는 것을 알고 있다면 배열 논리를 수행 할 수 있습니다. 이 코드 줄이 실행될 때마다 1과 2 사이의 값을 바꿉니다.

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

0

다음과 같이 할 수 있습니다.

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

또는 두 개 이상의 변수를 바꿀 때 make_tuple을 사용하십시오.

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

그러나 내부적으로 std :: tie가 임시 변수를 사용하는지 여부는 확실하지 않습니다!


0

자바 스크립트에서 :

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
}

두 옵션의 실행 시간에 유의하십시오.

이 코드를 실행하여 측정했습니다.

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

보시다시피 (그리고 많은 사람들이 말했듯이) 제자리에 스왑 (xor)은 임시 변수를 사용하는 다른 옵션보다 많은 시간이 걸립니다.


0

R에는 Edsger W. Dijkstra가 A Discipline of Programming , 1976, ch.4, p.29 에서 제안한 동시 할당이 누락되었습니다 . 이것은 우아한 솔루션을 허용합니다.

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

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

매우 간단하지만 경고가 발생할 수 있습니다.


5
작동하지 않는다는 경고? b=a이 이전 또는 이후에 수행 되는지 여부 는 알 수 없습니다 a + b.
Bo Persson 2013

-1

c 언어로 두 값을 교환하기위한 한 줄 솔루션.

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

오버플로시 정의되지 않은 동작입니다.
Keith Thompson

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

작업이 오버플로되거나 언더 플로되면 정의되지 않은 동작이 발생합니다. 또한 객체가 부동 소수점 인 경우 정밀도가 떨어질 수 있습니다.
Keith Thompson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.