• 两个数交换的讨论


    两个数交换的讨论

             C语言课中,两个数交换的程序必定会涉及,尤其是在讲解如何传参时。这里我们重点讨论一下两个数交换有哪几种方式,以及其原理是什么。

             首先,我们给出几种两个数交换的代码,然后逐一讨论:

    #include <iostream>
    #include <vector>
    using namespace std;
    
    void swap1(int& a, int& b)
    {
        int t = a;
        a = b;
        b = t;
    }
    
    void swap2(int& a, int& b)
    {
        a = a + b;
        b = a - b;
        a = a - b;
    }
    
    void swap3(int& a, int& b)
    {
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;
    }
    
    void swap4(int& a, int& b)
    {
        if (&a == &b)
        {
            return;
        }
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;
    }
    
    void swap5(int& a, int& b)
    {
        if (a == 0 && b == 0)
        {
            ;
        }
        else if (a == 0 && b != 0)
        {
            a = b;
            b = 0;
        }
        else if (a != 0 && b == 0)
        {
            a = 0;
            b = a;
        }
        else
        {
            a = a * b;
            b = a / b;
            a = a / b;
        }
    }
    
    void swap6(int& a, int& b)
    {
        a = a - b;
        b = b + a;
        a = b - a;
    }
    
    void swap7(int& a, int& b)
    {
        a = a + b - (b = a);
    }
    
    void swap8(int& a, int& b)
    {
        a ^= b ^= a ^= b;
    }
    
    void swap9_three(int& a, int& b, int& c)
    {
        c = a + c - (a = b, b = c);
    }
    
    void swap10_n(vector<int>& a)
    {
        for (auto i = 0; i < a.size() - 1; ++i)
        {
            swap8(a[i], a[i + 1]);
        }
    }
    
    int main()
    {
        return 0;
    }

    1.最常规的做法

             swap1是我们最常见也是最直观的做法,就是设定一个临时量来暂存其中一个待交换数值。

    2.利用两个数之间的和

             swap2是利用了待交换两数的和,具体如下:

           a = a + b

           b = a – b = (a + b) – b = a

           a = a – b = (a + b) – a = b

    3.利用异或

             根据异或运算的特点:

    参数1

    运算

    参数2

    结果

    0

    异或

    0

    0

    0

    1

    1

    1

    0

    1

    1

    1

    0

             参数1相对于参数2来说,如果参数2为0,则参数1不变,如果参数2为1,则参数1翻转。也就是说0保持,1翻转。

             进而可以推导出 a ^ a = 0,因为如果都为0则为0,如果都为1,由于翻转也为0

             a ^ 0 = a

             根据该特性,我们有如下算法:

           a = a ^ b

           b = a ^ b = (a ^ b) ^ b = a 说明:b ^ b = 0

           a = a ^ b = (a ^ b) ^ a = b 说明:a ^ b = 0

             同或是异或的相反,也就是说 a 同或 b = ~(a ^ b)

    参数1

    运算

    参数2

    结果

    0

    同或

    0

    1

    0

    1

    0

    1

    0

    0

    1

    1

    1

    4.异或的一个漏洞

             swap3是在a和b不是内存中的同一个对象的情况适用的,如果a和b都是同一个对象的引用,则:

           a = a ^ b = 0

           b = a ^ b = 0 ^ 0 = 0

           a = a ^ b = 0 ^ 0 = 0

             最终,导致 a = b = 0。

             所以,我们需要考虑a和b是否同时引用了同一个内存对象,这就有了swap4,检测&a == &b

             其实,每个swap函数都需要先检测待交换的两个数是否引用了同一个内存变量,如果引用了同一个内存变量,则需要立即返回。

    5.利用两个数的商

             根据swap2的思想:利用两个数的和,我们利用两个数的商。但是由于存在0的情况,所以需要分为四种情况来处理:

           a == 0 && b == 0

           a == 0 && b != 0

           a != 0 && b == 0

           a != 0 && b != 0

             对于有其中一个变量为0的时候,会导致:

           a = a * b = 0 * b = 0

           b = a / b = 0 / b = 0

           a = a / b = 0 / 0:异常

    6.利用两个数的差

             原理和利用两个数的和差不多:

           a = a – b

           b = b + a = b + (a - b) = a

           a = b – a = a – (a - b) = b

    7.合并

             a = a + b – (b = a)

             其效果是:b = a

             a = a + b – (b = a) = a + b – a = b

    8.异或合并

             a ^= b ^= a ^= b

             等价于:

             a ^= b

             b ^= a

             a ^= b

             也就是说:

             a = a ^ b;

             b = b ^ a = b ^ (a ^ b) = a

             a = a ^ b = (a ^ b) ^ a = b

    9.三个数交换

             3个数交换其实有很多种组合。

             3! = 6

             a、b、c三个数,如果保持不变,则有:a、b、c

             如果其中2个不变,则第三个也不变

             如果其中一个不变,则有:a、c、b;c、b、a;b、a、c

             如果3个全变,则有:b、c、a;c、a、b

             我们这里是采用b、c、a的形式:

             c = a + c – (a = b, b = c)

             其等价于:

             a = b

             b = c

             c = a + c – c = a

    10.n个数的交换

             对于n个数的情况,n个数总共有n!个组合。

             我们采用b、c、a的形式:遍历n个数,依次交换相邻的两个数即得。

    总结

             以上我们讨论了2个数如何进行交换,参数传递都为引用传参(交换两个值必须引用传递),但是需要考虑的一点就是两个数不能同时引用同一个内存变量,否则将导致交换失败,原来的值被改的。

             所以,不仅仅swap4需要检测&a == &b,每个swap函数都需要检测。如果&a == &b则马上返回,否则进行进一步的交换操作。

  • 相关阅读:
    PHP探针
    服务器fsockopen函数和pfsockopen函数开启及作用
    WP SMTP插件为啥我一直设置的不对?
    用WP SMTP插件实现邮件发送功能
    openssl基本原理 + 生成证书 + 使用实例
    解决wordpress无法发送邮件的问题|配置好WP-Mail-SMTP的前提
    使用 openssl 生成证书
    如何使用OpenSSL工具生成根证书与应用证书
    OpenSSL 给自己颁发根证书,由根证书签发下级证书的步骤。
    ARMCC和GCC编译ARM代码的软浮点和硬浮点问题【转】
  • 原文地址:https://www.cnblogs.com/unixfy/p/3291291.html
Copyright © 2020-2023  润新知