तीसरे चर का उपयोग किए बिना दो चर मान का स्वैप करना


104

एक इंटरव्यू में पूछे गए बहुत ही ट्रिकी सवालों में से एक।

जैसे दो चर का मान स्वैप करें a=10और b=15

आम तौर पर दो चर मानों की अदला-बदली करने के लिए, हमें 3 चर की आवश्यकता होती है जैसे:

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

अब आवश्यकता है, 3 जी चर का उपयोग किए बिना दो चर के स्वैप मूल्यों की।


76
वाह। एक खराब चुना हुआ साक्षात्कार प्रश्न IMHO। यह एक ऐसी तकनीक है जो शायद ही कभी, अगर कभी व्यवहार में उपयोगी हो। एक अच्छा मौका है कि यह केवल "अस्थायी स्वैप" की तुलना में कम कुशल कोड के परिणामस्वरूप संकलक के ऑप्टिमाइज़र को भ्रमित करेगा। जब तक आप जिस स्थान पर साक्षात्कार कर रहे थे वह बहुत गणित-भारी सामान में शामिल हो जाता है (विचार करें: एन्क्रिप्शन एल्गोरिथम विकास या इस तरह) मैं इस तरह के सवाल पूछने के लिए किसी भी अच्छे कारण की कल्पना नहीं कर सकता।
डैन मोल्डिंग

10
वास्तव में, यह सवाल आपको कुछ और नहीं बताता है कि क्या उम्मीदवार इस विशेष चाल को जानता है जो उत्पादन कोड में बहुत बेकार है। मुझे लगता है कि आप कभी-कभार जादूगर पर दौड़ सकते हैं जो इसे उड़ने के बारे में बताते हैं, लेकिन लोगों को यह पसंद है जो पहले से नहीं जानते हैं कि यह ट्रिक बहुत दुर्लभ है।
ceo

2
मई-क्या वे ऐसे लोगों को मात देना चाहते हैं जो सोचते हैं कि ऐसी तरकीबें जो अच्छा प्रोग्रामर बनाती हैं? इसके अलावा, जब एक्सोर-ट्रिक के बारे में पढ़ रहे हों, तो ध्यान दें कि यह कब विफल होगा (जो कि आईएमओ सामान्य-उद्देश्य पूर्णांक स्वैपिंग के लिए इसे पूरी तरह से बेकार बना देता है)।
चाचा 15

जवाबों:


155

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) = 0यदि x और y दोनों समान मेमोरी लोकेशन साझा करते हैं, जब कोई 0 पर सेट होता है, तो दोनों 0. पर सेट होते हैं। जब दोनों * x और * y 0 होते हैं, तो अन्य सभी xor ऑपरेशन * x और * y के बराबर होंगे 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 एक ही वस्तु का संदर्भ देते हैं)।
dmckee --- एक्स-मॉडरेटर ने बिल्ली के बच्चे को

1
मुझे नहीं पता है कि जब कोड इतना टूट गया है तो यह बहुत सारे अपवॉट कैसे हो गए। परीक्षण किए गए कोड सेगमेंट में दोनों स्वैप पूरी तरह से गलत हैं। पास देखो।
साबुनबॉक्स

@ SapapBox: बहुत अच्छी बात! XOR स्वैप शून्य x और पत्तियां y अछूता है, और अस्थायी स्वैप दोनों x के मान से छोड़ता है। ओह!
ड्रू हॉल

4
@SoapBox अच्छी पकड़। निश्चित और फिर से परीक्षण किया गया और मुझे समय में कोई बड़ा अंतर नहीं मिला।
याकोबी

4
प्रश्नकर्ता ने कहा कि दो वेरिएबल्स हैं, इनटस नहीं। : पी
प्लूमनेटर

93

सामान्य रूप है:

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

हालाँकि, आपको संभावित रूप से ओवरफ्लो देखने की जरूरत होती है और सभी ऑपरेशनों का उलटा भी नहीं होता है जो कि उन सभी मूल्यों के लिए अच्छी तरह से परिभाषित होते हैं जिन्हें ऑपरेशन परिभाषित किया गया है। जैसे * और / तब तक काम करना जब तक A या B 0 न हो

एक्सआर विशेष रूप से मनभावन है क्योंकि यह सभी ints के लिए परिभाषित किया गया है और इसका स्वयं का व्युत्क्रम है


XOR (X, X) == 0, इसलिए जब दोनों मानों की अदला-बदली नहीं हो रही हो, तो xor ints EXCEPT के लिए काम करता है। मैं यह इंगित करने वाला पहला व्यक्ति नहीं हूं और बहुत से लोगों ने इसे (यहां और अन्य जगहों पर) क्रेडिट के लिए किसी को भी बाहर करने के लिए कहा है।
एलन

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

16
a+bओवरफ्लो होने पर क्या होगा ?
आलोक सिंघल

2
@ आलोक: यह विचार में नहीं लिया गया, इस प्रकार यह अव्यावहारिक है :)
डोर

4
यदि a और b एक ही, मूल, आकार पूर्णांक प्रकार (जैसे int, unsigned short...) के हैं, तो यह अभी भी अंत में बाहर काम करता है, यहां तक ​​कि अतिप्रवाह के साथ भी, क्योंकि यदि a + b ओवरफ्लो होता है, तो a - b कम हो जाएगा। इन मूल पूर्णांक प्रकारों के साथ, मान केवल रोलओवर करते हैं।
पैट्रिक जॉम्नियर

11
C में, unsignedपूर्णांक प्रकारों पर इसका उपयोग करना ठीक है और हमेशा काम करता है। हस्ताक्षरित प्रकारों पर, यह अतिप्रवाह पर अपरिभाषित व्यवहार का आह्वान करेगा।
jpalecek

2
@ शहबाज़: साइन किए गए पूर्णांक 2 के पूरक में संग्रहीत किए जाने पर भी, अतिप्रवाह पर व्यवहार अभी भी अपरिभाषित है।
कीथ थॉम्पसन

79

किसी ने भी उपयोग करने का सुझाव नहीं दिया std::swap, फिर भी।

std::swap(a, b);

मैं किसी भी अस्थायी चर का उपयोग नहीं करता हूं और इसके प्रकार पर निर्भर करता है aऔर bकार्यान्वयन में एक अनुमान लगाया जा सकता है जो या तो नहीं होता है। कार्यान्वयन को यह जानना चाहिए कि क्या एक 'चाल' उपयुक्त है या नहीं। दूसरे अनुमान की कोशिश करने का कोई मतलब नहीं है।

अधिक आम तौर पर, मैं शायद ऐसा कुछ करना चाहता हूं, क्योंकि यदि संभव हो तो बेहतर अधिभार खोजने के लिए एडीएल को सक्षम करने वाले वर्ग प्रकारों के लिए यह काम करेगा।

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

बेशक, इस उत्तर के लिए साक्षात्कारकर्ता की प्रतिक्रिया रिक्ति के बारे में बहुत कुछ कह सकती है।


बेशक C ++ 0x स्वैप में रैवल्यू रेफरेंस का उपयोग किया जाएगा इसलिए यह और भी बेहतर होगा!
जे.के.

16
हर कोई चमकदार एक्सोर या उनके द्वारा सीखी जाने वाली अन्य चाल के बारे में बताना चाहता है कि इसे कैसे उपयोग करना है, लेकिन यह सबसे अच्छा जवाब है।

2
std क्यों नहीं :: swap (a, b); ? मेरा मतलब है क्यों का उपयोग कर?
दिनाज

2
@ डिनीज़ के बिना std::, यूज़र-डिफ़ाइंड टाइप्स के लिए यूज़र-डिफ़ाइंड इंप्लीमेंटेशन swapभी कॉल करने के लिए उपलब्ध हैं (इसका मतलब "यह है कि यह क्लास के टाइप्स के लिए काम करेगा ताकि ADL को बेहतर ओवरलोड मिल सके।"
काइल स्ट्रैंड

std::swapइसके कार्यान्वयन में अतिरिक्त अस्थायी मेमोरी का उपयोग करता है? cplusplus.com/reference/utility/swap
निंजा

19

जैसा कि पहले से ही मनु द्वारा उल्लेख किया गया है, एक्सओआर एल्गोरिथ्म एक लोकप्रिय है जो सभी पूर्णांक मानों के लिए काम करता है (जिसमें कुछ किस्मत और कास्टिंग के साथ संकेत शामिल हैं)। पूर्णता के लिए मैं इसके अलावा / घटाव के साथ एक और कम शक्तिशाली एल्गोरिदम का उल्लेख करना चाहूंगा:

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

यहां आपको ओवरफ्लो / अंडरफ्लो से सावधान रहना होगा, लेकिन अन्यथा यह ठीक काम करता है। तुम भी इस मामले में फ्लोट / युगल पर कोशिश कर सकते हैं XOR उन पर अनुमति नहीं है।


" सभी पूर्णांक मान (जिसमें संकेत शामिल हैं) " - क्या? नहीं, संकेत पूर्णांक नहीं हैं, और आप पॉइंटर पॉइंटर मान नहीं ले सकते। आप फ्लोटिंग-पॉइंट वैल्यू भी नहीं कर सकते। लेकिन जोड़ / घटाव विधि में अतिप्रवाह या अंडरफ्लो पर अपरिभाषित व्यवहार (हस्ताक्षरित या फ्लोटिंग-पॉइंट प्रकार के लिए) होता है, फ्लोटिंग-पॉइंट के लिए सटीक खो सकता है, और पॉइंटर्स या अन्य गैर-संख्यात्मक प्रकारों पर लागू नहीं किया जा सकता है।
कीथ थॉम्पसन

@KeithThompson - ठीक है, फ्लोटिंग पॉइंट्स के लिए सटीक का नुकसान सही है, लेकिन परिस्थितियों के आधार पर, यह स्वीकार्य हो सकता है। संकेत के रूप में - ठीक है, मैंने कभी भी एक कंपाइलर / प्लेटफ़ॉर्म के बारे में नहीं सुना है जहाँ पॉइंटर्स को पूर्णांक और बैक पर फिर से डाला नहीं जा सकता है (सही आकार के पूर्णांक को चुनने के लिए ध्यान रखना)। लेकिन फिर, मैं C / C ++ विशेषज्ञ नहीं हूं। मुझे पता है कि यह मानक के विरूद्ध है, लेकिन मैं इस धारणा के तहत था कि यह व्यवहार ... सब कुछ के अनुरूप है।
विल्क्स-

1
@ विलक्स-: अस्थायी चर का उपयोग करके इसे टालना इतना आसान होने पर परिशुद्धता का नुकसान स्वीकार्य क्यों होगा - या std::swap()? निश्चित रूप से, आप पॉइंटर्स को पूर्णांकों में और फिर से वापस बदल सकते हैं (यह मानते हुए कि एक बड़ा पर्याप्त पूर्णांक प्रकार है, जिसकी गारंटी नहीं है), लेकिन यह वही नहीं है जो आपने सुझाया था; आप ने सूचित किया कि संकेत दिए गए हैं पूर्णांकों, नहीं है कि वे पूर्णांकों में बदला जा सकता। हां, स्वीकृत उत्तर संकेत देने वालों के लिए काम नहीं करेगा। चार्ल्स बेली के जवाब का उपयोग std::swapकरना वास्तव में एकमात्र सही है।
कीथ थॉम्पसन

1
सबसे पहले, सवाल था "तीसरे चर का उपयोग किए बिना स्वैप कैसे करें" और उसके लिए दिया गया कारण "एक साक्षात्कार प्रश्न" था। मैंने सिर्फ एक अन्य संभावित उत्तर दिया। दूसरा, ठीक है, संकेत देने के लिए मेरी क्षमा याचना पूर्णांक हैं। मैंने जवाब को उम्मीद से अधिक स्पष्ट और सही होने के लिए अद्यतन किया। कृपया मुझे सही करें अगर मैं अभी भी गलत हूं (या स्वयं उत्तर अपडेट करें)। तीसरा, मैंने स्वीकृत उत्तर के बारे में हिस्सा हटा दिया। यह कहीं भी सूचक-से-पूर्णांक कलाकारों का उपयोग नहीं कर रहा है और यह सही तरीके से काम करता है (जहां तक ​​मैं समझता हूं)।
विल्क्स-

@KeithThompson: इस सवाल को संशोधित किया जा सकता है कि std::swapतीसरे चर का उपयोग किए बिना इसे कैसे लागू किया जा सकता है।
jxh

10

मूर्खतापूर्ण प्रश्न उपयुक्त उत्तर के लायक हैं:

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

registerकीवर्ड का एकमात्र अच्छा उपयोग ।


1
क्या भंडारण-वर्ग रजिस्टर के साथ घोषित की गई वस्तु "परिवर्तनशील" नहीं है? इसके अलावा, मुझे यकीन नहीं है कि यह रजिस्टर का एक अच्छा उपयोग है, क्योंकि यदि आपका कंपाइलर पहले से ही इसे ऑप्टिमाइज़ नहीं कर सकता है, तो भी कोशिश करने की क्या बात है, आपको या तो जो भी बकवास मिले उसे स्वीकार करना चाहिए या असेंबली खुद लिखना चाहिए ;-) लेकिन जैसा कि आप कहते हैं, एक डोडी प्रश्न एक डोडी उत्तर के योग्य है।
स्टीव जेसोप डे

1
बहुत सारे आधुनिक कंपाइलर रजिस्टर स्टोरेज क्लास को नजरअंदाज कर देते हैं, क्योंकि उन्हें इस बात का ज्यादा बेहतर अंदाजा होता है कि आप जो करते हैं, वह अक्सर एक्सेस हो जाता है।
सीईओ

6
ध्यान दें कि यह उत्तर साक्षात्कार (एर) के लिए है, न कि संकलक के लिए। यह विशेष रूप से इस तथ्य का लाभ उठाता है कि इस तरह के प्रश्न पूछने वाले साक्षात्कारकर्ता वास्तव में C ++ को नहीं समझते हैं। इसलिए, वे इस उत्तर को अस्वीकार नहीं कर सकते। (और कोई मानक उत्तर नहीं है; आईएसओ सी ++ वस्तुओं के बारे में बात करता है चर नहीं)।
MSalters

आह, मैं तुम्हें ले आता हूं। मैं एक मानक के रूप में संज्ञा के रूप में उल्लेख करने के लिए सी मानक देख रहा था, और न केवल गैर-अर्थ का मतलब है। मुझे n1124 में एक मिला, लूप्स के लिए अनुभाग में "शुरुआती" में घोषित "चर" के दायरे को परिभाषित करता है। तब मुझे एहसास हुआ कि सवाल सी ++ था, और यह देखने के लिए कि सी ++ ने कहीं भी एक ही टाइपो बना दिया है या नहीं, यह देखने के लिए खोज करने की जहमत नहीं उठाई।
स्टीव जेसोप

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:"
12:25 पर user253751

कई अन्य जवाबों के साथ, यह अपरिभाषित व्यवहार है यदि a+bया a-bओवरफ्लो होता है। इसके अलावा, void main()अमान्य है और <conio.h>गैर-मानक है।
कीथ थॉम्पसन

2

मूल समाधान के बाद से है:

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

आप इसका उपयोग करके दो लाइनर बना सकते हैं:

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

फिर इसका उपयोग करके एक लाइनर बनाएं:

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

1
अपरिभाषित व्यवहार। yकोई हस्तक्षेप अनुक्रम बिंदु के साथ एक ही अभिव्यक्ति में पढ़ा और लिखा जाता है।
कीथ थॉम्पसन

1

यदि आप चर के बजाय 2 विधानसभा रजिस्टरों के बारे में पूछने के लिए थोड़ा सवाल बदलते हैं, तो आप xchgऑपरेशन को एक विकल्प के रूप में भी उपयोग कर सकते हैं , और एक के रूप में स्टैक ऑपरेशन।


1
आप किस xchgऑपरेशन की बात कर रहे हैं? प्रश्न सीपीयू आर्किटेक्चर को निर्दिष्ट नहीं करता है।
कीथ थॉम्पसन

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
अतिप्रवाह पर अपरिभाषित व्यवहार है।
कीथ थॉम्पसन

1
इसके अलावा, C ++ में, यह अवांछनीय व्यवहार हो सकता है जब मान एक ही प्रकार के नहीं होते हैं। उदाहरण के लिए, a=10और b=1.5
मैथ्यू कोल

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

कृपया भविष्य के आगंतुकों के लिए अपने उत्तर में संक्षिप्त विवरण जोड़ें।
निकोले मिहायलोव

1
इसमें हम उपयोगकर्ता से दो पूर्णांकों का इनपुट ले रहे हैं। तब हम बिटवाइस एक्सर ऑपरेशन दो स्वैप का उपयोग कर रहे हैं। मान लें कि हमारे पास दो अंतराल हैं a = 4 और b = 9 तो अब a = b a> b -> 13 = 4 ^ 9 b = a ^ b -> 4 = 13 ^ 9 a a b -> 9 = 13 ^ 9
नईम उल हसन

1

यहाँ एक और समाधान है, लेकिन एक ही जोखिम है।

कोड:

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

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

स्थान + 1 पर किसी भी मूल्य को ओवरराइड किया जाएगा।


2
यह एक उपयोगी उत्तर था, शायद मूल्य गायब हो गया।
बीबी ताहिरा

1
कई प्रकार के अपरिभाषित व्यवहार। *(&a+1)अच्छी तरह से हो सकता है bvoid main()अमान्य है। <conio.h>गैर-मानक है (और आप इसका उपयोग भी नहीं करते हैं)।
कीथ थॉम्पसन

कोड को अन्य आउटपुट मापदंडों के साथ परीक्षण किया गया था, जिसे बाहर रखा गया था, जैसा कि मैंने एक जोखिम का उल्लेख किया है। स्मृति का जोखिम अधिक हो गया है .. यह वहाँ है .. लेकिन यह तीसरे की भागीदारी के बिना एक उपयोगी स्वैपिंग दो चर था।
डेयरडेविल

सबसे बुरी बात यह है कि यह वास्तव में कुछ समय काम कर सकता है, इसलिए आप तुरंत महसूस नहीं कर सकते कि यह पूरी तरह से टूट गया है और अनुकूलन, अन्य संकलक, आदि के तहत असफल हो जाएगा
avl_sweden

1

बेशक, सी ++ जवाब होना चाहिए 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;
      }
   }
}

आपको यह सुनिश्चित करना होगा कि मेमोरी स्थान अलग हैं और यह भी कि वास्तविक मूल्य अलग हैं क्योंकि ए एक्सओआर ए = 0


आपको यह सुनिश्चित करने की आवश्यकता नहीं है कि मान अलग-अलग हैं।
user253751

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दोनों को एक ही अभिव्यक्ति के भीतर पढ़ा और संशोधित किया गया है, जिसमें कोई हस्तक्षेप करने वाला अनुक्रम बिंदु नहीं है।
कीथ थॉम्पसन


0

सबसे अच्छा जवाब XOR का उपयोग करना और एक पंक्ति में इसका उपयोग करना अच्छा होगा।

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

x, y वैरिएबल हैं और उनके बीच अल्पविराम अनुक्रम बिंदुओं का परिचय देता है इसलिए यह संकलक पर निर्भर नहीं बनता है। चीयर्स!


0

चलो तीसरे चर का उपयोग किए बिना दो नंबर स्वैप करने के लिए एक सरल सी उदाहरण देखें।

कार्यक्रम 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 एक संख्या देता है जिसमें सभी बिट्स 1 के रूप में होते हैं जहाँ भी x और y के बिट भिन्न होते हैं। उदाहरण के लिए, 10 का XOR (बाइनरी 1010 में) और 5 (बाइनरी 0101 में) 1111 और 7 (0111) का XOR और 5 (0101) (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);

मैं किसी भी अस्थायी चर का उपयोग नहीं करता हूं और ए और बी के प्रकार के आधार पर कार्यान्वयन में एक विशेषज्ञता हो सकती है जो या तो नहीं होती है। कार्यान्वयन को यह जानना चाहिए कि क्या एक 'चाल' उपयुक्त है या नहीं।

उपरोक्त तरीकों से समस्याएँ:

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

लेकिन मुझे यकीन नहीं है कि आंतरिक रूप से एसटीडी :: टाई एक अस्थायी चर का उपयोग करता है या नहीं!


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

आर एक समवर्ती कार्य याद कर रहा है, जैसा कि ए डिसिप्लिन ऑफ़ प्रोग्रामिंग , 1976, ch.4, p.29 में Edsger W. Dijkstra द्वारा प्रस्तावित है । यह एक सुंदर समाधान के लिए अनुमति देगा:

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

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

यह बहुत आसान है, लेकिन यह एक चेतावनी बढ़ा सकता है।


5
चेतावनी दी जा रही है कि यह काम नहीं करता है? हम नहीं जानते कि क्या b=aपहले या बाद में किया जाता है a + b
बो पर्सन

-1

सी भाषा में दो मानों की अदला-बदली के लिए एकल पंक्ति समाधान।

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

अतिप्रवाह पर अपरिभाषित व्यवहार।
कीथ थॉम्पसन

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

यदि कोई ऑपरेशन ओवरफ्लो या अंडरफ्लो होता है तो इसका अपरिभाषित व्यवहार होता है। यदि ऑब्जेक्ट फ़्लोटिंग-पॉइंट हैं, तो यह परिशुद्धता भी खो सकता है।
कीथ थॉम्पसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.