• 小朋友学算法(2)


    深入理解动态规划

    先看一道北大POJ上的题:
    http://poj.org/problem?id=1163

     
    1.png

    在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或右下走。只需要求出这个最大和即可,不必给出具体路径。 三角形的行数大于1小于等于100,数字为 0 - 99。

    输入格式:

    5      //这一行的数字表示三角形行数,下面几行输入三角形
    7
    3   8
    8   1   0
    2   7   4   4
    4   5   2   6   5
    

    要求输出最大和

    一、递归实现

    用num( row, col) 来表示第r行第 j 个数字(r,j从1开始算)
    用MaxSum(row, col)表示从num(row, col)到底边的各条路径中,最佳路径的数字之和。
    因此,此题的问题就变成了求 MaxSum(1,1)
    从num(row, col)出发,下一步只能走num(row + 1, col)或者num(row + 1, col + 1)。故对于N行的三角形,我们可以写出如下的递归式子:

    if ( N == row)                  
        MaxSum(row, col) = num(row, col)    
    else        
    MaxSum(row, col) = Max{ MaxSum(row+1, col), MaxSum(row + 1, col + 1) } + num(row, col)
    

    完整代码:

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define MAX 101
    int num[MAX][MAX];
    int n;
    
    int MaxSum(int row, int col)
    {
        if(n == row)
        {
            return num[row][col];
        }
    
        return max(MaxSum(row + 1, col), MaxSum(row + 1, col + 1)) + num[row][col];
    }
    
    int main()
    {
        int row, col;
        cin >> n;
    
        for(row = 1; row <= n; row++)
        {
            for(col = 1; col <= row; col++)
            {
                cin >> num[row][col];
            }
        }
    
        cout << MaxSum(1,1) << endl;
    }
    

    运行结果:

    5
    7
    3 8
    8 1 0
    2 7 4 4
    4 5 2 6 5
    30
    

    这个程序提交上去会超时,因为递归会包含大量的重复计算。

    具体的计算步骤如下:
    MaxSum(1, 1) = max(MaxSum(2, 1) + MaxSum(2, 2)) + num(1, 1)
    MaxSum(2, 1) = max(MaxSum(3, 1) + MaxSum(3, 2)) + num(2, 1)
    MaxSum(3, 1) = max(MaxSum(4, 1) + MaxSum(4, 2)) + num(3, 1)
    MaxSum(4, 1) = max(MaxSum(5, 1) + MaxSum(5, 2)) + num(4, 1)
    MaxSum(5, 1)直接返回4
    MaxSum(5, 2)直接返回5
    MaxSum(4, 2) = max(MaxSum(5, 2) + MaxSum(5, 3)) + num(4, 2)
    MaxSum(5, 2)直接返回5
    MaxSum(5, 3)直接返回2
    MaxSum(3, 2) = max(MaxSum(4, 2) + MaxSum(4, 3)) + num(3, 2)
    MaxSum(4, 2) = max(MaxSum(5, 2) + MaxSum(5, 3)) + num(4, 2)
    MaxSum(5, 2)直接返回5
    MaxSum(5, 3)直接返回2
    MaxSum(4, 3) = max(MaxSum(5, 3) + MaxSum(5, 4)) + num(4, 3)
    MaxSum(5, 3)直接返回2
    MaxSum(5, 4)直接返回6
    MaxSum(2, 2) = max(MaxSum(3, 2) + MaxSum(3, 3)) + num(2, 2)
    MaxSum(3, 2) = max(MaxSum(4, 2) + MaxSum(4, 3)) + num(3, 2)
    MaxSum(4, 2) = max(MaxSum(5, 2) + MaxSum(5, 3)) + num(4, 2)
    MaxSum(5, 2)直接返回5
    MaxSum(5, 3)直接返回2
    MaxSum(4, 3) = max(MaxSum(5, 3) + MaxSum(5, 4)) + num(4, 3)
    MaxSum(5, 3)直接返回2
    MaxSum(5, 4)直接返回6
    MaxSum(3, 3) = max(MaxSum(4, 3) + MaxSum(4, 4)) + num(3, 3)
    MaxSum(4, 3) = max(MaxSum(5, 3) + MaxSum(5, 4)) + num(4, 3)
    MaxSum(5, 3)直接返回2
    MaxSum(5, 4)直接返回6
    MaxSum(4, 4) = max(MaxSum(5, 4) + MaxSum(5, 5)) + num(4, 4)
    MaxSum(5, 4)直接返回6
    MaxSum(5, 5)直接返回5

    可以统计出,每个数被计算的次数如下图所示:

     
    2.png

    二、动态规划

    (一)记忆递归

    每算出一个MaxSum(row, col)就保存起来,下次用到其值的时候直接取用,则可免去重复计算。那么可以用n方的时间复杂度完成计算,因为三角形的数字总数是 n(n+1)/2

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define MAX 101
    int num[MAX][MAX];
    int n;
    int maxSum[MAX][MAX];
    
    int MaxSum(int row, int col)
    {
        if(-1 != maxSum[row][col])
        {
            return maxSum[row][col];
        }
    
        if(n == row)
        {
            maxSum[row][col] = num[row][col];
        }
    
        return max(MaxSum(row + 1, col), MaxSum(row + 1, col + 1)) + num[row][col];
    }
    
    int main()
    {
        int row, col;
        cin >> n;
    
        for(row = 1; row <= n; row++)
        {
            for(col = 1; col <= row; col++)
            {
                cin >> num[row][col];
                maxSum[row][col] = -1;
            }
        }
    
        cout << MaxSum(1,1) << endl;
    }
    

    (二)优化方案一(递推)

    递归会造成大量的重复计算,即使是把结果存储起来,仍旧要重复去取值。
    可以考虑用递推的方法,从最后一行开始计算。
    (1)把最后一行直接写出

    *****
    * * * * *
    * * * * *
    * * * * *
    4 5 2 6 5

    (2)倒数第2行
    maxSum[4][1] = max(2 + 4, 2 + 5) = 7
    maxSum[4][2] = max(7 + 5, 7 + 2) = 12
    maxSum[4][3] = max(4 + 2, 4 + 6) = 10
    maxSum[4][4] = max(4 + 6, 4 + 5) = 10

    *****
    * * * * *
    * * * * *
    7 12 10 10 *
    4 5 2 6 5

    (3)倒数第3行
    maxSum[3][1] = max(8 + 7, 8 + 12) = 20
    maxSum[3][2] = max(1 + 12, 1 + 10) = 13
    maxSum[3][3] = max(0 + 10, 0 + 10) = 10

    *****
    * * * * *
    20 13 10 * *
    7 12 10 10 *
    4 5 2 6 5

    (4)倒数第4行
    maxSum[2][1] = max(3 + 20, 3 + 13) = 23
    maxSum[2][2] = max(8 + 13, 8 + 10) = 21

    *****
    23 21 * * *
    20 13 10 * *
    7 12 10 10 *
    4 5 2 6 5

    (5)倒数第5行
    max[1][1] = max(7 + 23, 7 + 21) = 30

    30****
    23 21 * * *
    20 13 10 * *
    7 12 10 10 *
    4 5 2 6 5

    代码实现:

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define MAX 101
    int num[MAX][MAX];
    int n;
    int maxSum[MAX][MAX];
    
    int main()
    {
        int row, col;
        cin >> n;
        for(row = 1; row <= n; row++)
        {
            for(col = 1; col <= row; col++)
            {
                cin >> num[row][col];
            }
        }
    
        for(int col = 1; col <= n; col++)
        {
            maxSum[n][col] = num[n][col];
        }
    
        for(int row = n - 1; row >= 1;  row--)
        {
            for( int col = 1; col <= row; col++)
            {
                maxSum[row][col] = max(maxSum[row + 1][col], maxSum[row + 1][col + 1]) + num[row][col];
            }
        }
    
        cout << maxSum[1][1] << endl;
    }
    

    (三)优化方案二(一维数组)

    int maxSum[101][101]总共占用了101 * 101 * 4 = 40804B = 40kB的内存空间。如果只用一维数组来存储结果的话,int maxSum[101] 总共只需占用101 * 4 = 404B的内存空间。
    方法是人底层一行行地向上递推。

    (1)最后一行原始数据

    45265

    (2)第四行第一列的最大值放在maxSum[1]中

    75265

    (3)第四行第二列的最大值放在maxSum[2]中

    712265

    (4)第四行第三列的最大值放在maxSum[3]中

    7121065

    (5)第四行第四列的最大值放在maxSum[4]中

    71210105

    (6)第三行第一列的最大值放在maxSum[1]中

    201210105

    (7)第三行第二列的最大值放在maxSum[2]中

    201310105

    (8)第三行第三列的最大值放在maxSum[3]中

    201310105

    (9)第二行第一列的最大值放在maxSum[1]中

    231310105

    (10)第二行第一列的最大值放在maxSum[2]中

    232110105

    (11)第一行第一列的最大值放在maxSum[2]中

    302110105

    代码实现:

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define MAX 101
    int num[MAX][MAX];
    int n;
    int maxSum[MAX];
    
    int main()
    {
        int row, col;
        cin >> n;
        for(row = 1; row <= n; row++)
        {
            for(col = 1; col <= row; col++)
            {
                cin >> num[row][col];
            }
        }
    
        for(int col = 1; col <= n; col++)
        {
            maxSum[col] = num[n][col];
        }
    
        for(int row = n - 1; row >= 1; row--)
        {
            for(int col = 1; col <= row; col++)
            {
                maxSum[col] = max(maxSum[col], maxSum[col + 1]) + num[row][col];
            }
        }
    
        cout << maxSum[1] << endl;
    }
    

    (四)优化方案三(不用额外数组)

    上一步中的maxSum[]一维数组也可以不要,直接把每一行的最大值存到num[][]中的最后一行即可。

    实现代码:

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define MAX 101
    int num[MAX][MAX];
    int n;
    int *maxSum;
    
    int main()
    {
        int row, col;
        cin >> n;
        for(row = 1; row <= n; row++)
        {
            for(col = 1; col <= row; col++)
            {
                cin >> num[row][col];
            }
        }
    
        maxSum = num[n];
    
        for(int row = n - 1; row >= 1; row--)
        {
            for(int col = 1; col <= row; col++)
            {
                maxSum[col] = max(maxSum[col], maxSum[col + 1]) + num[row][col];
            }
        }
    
        cout << maxSum[1] << endl;
    }
    

    注意,优化方案二和优化方案三,都只是节省空间,不能节省时间。



    向Java数组添加一个元素

    程序:

    public class ListInsert {
        public static long[] insert(long[] arr, int atIndex, long num){
            
            //新建数组,对原数组扩容
            long[] newArr = new long[arr.length + 1];
            
            int i = 0;
            for(; i < atIndex; i++){
                newArr[i] = arr[i];
            }
            
            //插入数据
            newArr[i] = num;
            
            //将大于index的数据向后移动一位
            for(int j = i; j < arr.length; j++){
                newArr[++i] = arr[j];
            }
    
            return newArr;
        }
        
        //测试
        public static void main(String[] args){
            long[] arr = {1,2,3,4,5};
            long[] arr1 = insert(arr, 2, 100);
            for (long l : arr1) {
                System.out.print(l + " ");
            }
        }
    }
    

    运行结果:

    1 2 100 3 4 5


    求组合数

    关于组合的介绍,可以参考小朋友学奥数(12):组合

    一、利用基本公式,递归

    #include <iostream>
    using namespace std;
    typedef long long ll;
    
    ll combination(ll n, ll k)
    {
        if(0 == k)
        {
            return 1;
        }
    
        return combination(n, k - 1) * (n - k + 1)/k;
    }
    
    int main()
    {
        cout << combination(10, 3) << endl;
        return 0;
    }
    

    运行结果:

    120
    

    分析:
     C(10, 3)
    = C(10, 2) * 8 / 3
    = C(10, 1) * 9 * 8 / (3 * 2)
    = C(10, 0) * 10 * 9 * 8 / (3 * 2 * 1)
    = 1 * 10 * 9 * 8 / (3 * 2 * 1)
    = 120

    二、利用基本性质,递归

    利用公式C(n, k) = C(n - 1, k) + C(n - 1, k - 1)

    #include <iostream>
    using namespace std;
    typedef long long ll;
    
    ll combination(ll n, ll k)
    {
        if(0 == k || n == k)
        {
            return 1;
        }
    
        if(1 == k)
        {
            return n;
        }
    
        return combination(n - 1, k) + combination(n - 1, k - 1);
    }
    
    int main()
    {
        cout << combination(10, 3)<< endl;
        return 0;
    }
    

    三、逆元+快速幂解法

    (一)基本概念

    上面两种方法都使用了递归方法,递归方法有个缺陷,就是在数据较大时效率较低。所以这里要介绍一个种新的求组合算法。在了解此算法之前,要先了解一些概念。

    1 同余

    同余是数论中的重要概念。
    给定一个正整数m,如果两个整数a和b满足a-b能够被m整除,即(a-b)/m得到一个整数,那么就称整数a与b对模m同余,记作a≡b(mod m)

    例1:4 ≡ 9 (mod 5),即4和9对模5同余

    例2:13 ≡ 23(mod 10),即13和23对模10同余

    2 模的加减乘除运算

    取模运算的等价变形适合加法、减法、乘法
    (a + b) % p = (a % p + b % p) % p
    (a - b) % p = (a % p - b % p) % p
    ( a * b) % p = (a % p * b % p) % p

    例3:(30 + 40) % 11 = 70 % 11 = 4
    (30% 11 + 40%11) % 11 = (8 + 7) % 11 = 15 % 11 = 4

    例4:(80 - 20) % 7 = 60 % 7 = 4
    (80 % 7 - 20 % 7) % 7 = (3 - 6) % 7 = -3 % 7 = 4 (取模是让商尽可能小,所以这里有 -3 / 7 = -1 …… 4)

    例5:(18 * 20) % 7 = 360 % 7 = 3
    (18%7 * 20%7)% 7 = (4 * 6)% 7 = 3

    但是,取模运算的等价变形不符合除法
    a/b % p ≠ (a%p / b%p) % p

    例6:(100 % 20)% 11 = 5 % 11 = 5
    (100%11 / 20%11) % 11 = (1 / 9) % 11 = 0 % 11 = 0

    3 逆元

    逆元:对于a和p,若gcd(a, p) = 1(a和p互素)且 a*b%p≡1,则称b为a%p的逆元。

    那这个逆元有什么用呢?试想一下求(a / b)%p,如果你知道b%p的逆元是c,那么就可以转变成(a/b)%p = (a/b) * 1 % p = (a / b) * (b* c % p) % p = a*c % p = (a%p) (c%p) % p,这样的话,除法运算就可以转化为乘法运算。

    那怎么求逆元呢?这时候就要引入强大的费马小定理!

    费马小定理:对于a和素数p,满足a^(p-1) % p ≡ 1
    

    接着因为a^(p−1) = a^(p−2) * a,所以有a^(p−2) * a % p ≡ 1。
    对比逆元的定义可得,a^(p−2)就是a的逆元。
    所以问题就转换成求解a^(p−2),即变成求快速幂的问题了。

    4 快速幂

    这部分的内容可以参考 小朋友学算法(6):求幂pow函数的四种实现方式 中的第四种方法

    (二)逆元 + 快速幂求组合思路

    现在目标是求C(n, m) %p,p为素数(经典p=1e9+7)。
    虽然有C(n, m) = n! / [m! (n - m)!],但由于取模的性质对于除法不适用,则有

     
    1.png

    所以需要利用逆元把“除法”转换成“乘法”,才能借助取模的性质计算组合数。

    求解C(n, m)%p的步骤:

    (1)通过循环,预先算好所有小于max_number的阶乘(%p)的结果,存到fac[max_number]里 (fac[i] = i! % p)
    (2)求m! % p的逆元(即求fac[m]的逆元):根据费马小定理,x%p的逆元为x^(p−2), 因此通过快速幂,求解fac[m]^(p−2) % p,记为M
    (3)求(n-m)! % p的逆元:同理就是求解fac[n−m]^(p−2) % p,记为NM
    (4)C(n, m) % p = ((fac[n] * M) % p * NM) % p

    (三) 算法代码

    #include <cstdio>
    using namespace std;
    
    #define MAX_NUMBER 100000
    //快速幂求x^n%mod
    long long quick_pow(long long x, long long n, long long mod)
    {
        long long res = 1;
        while (n)
        {
            if (n & 1)
            {
                res = res * x % mod;
            }
    
            x = x * x % mod;
            n >>= 1;
        }
    
        return res;
    }
    
    long long fac[MAX_NUMBER+5];
    long long n, m, p;
    
    int main()
    {
        while (~scanf("%lld %lld %lld", &n, &m, &p))
        {
            //预处理求fac,fac[i] = i!%p
            fac[0] = 1;
            for (int i = 1; i <= n; i++)
            {
                fac[i] = fac[i - 1] * i % p;
            }
            //组合数 = n!*(m!%p的逆元)*((n-m)!%p的逆元)%p
            printf("%lld
    ", fac[n] * quick_pow(fac[m], p - 2, p) % p * quick_pow(fac[n - m], p - 2, p) % p);
        }
    }
    

    运行结果:

    10000 5000 100000007
    93446621


    分割字符串

    一、准备知识

    在分割字符串之前,先来了解一些跟字符串相关的变量或函数:
    (1)size_type:size_type由string类类型和vector类类型定义的类型,用以保存任意string对象或vector对象的长度,标准库类型将size_type定义为unsigned类型。

    (2)string的find("x")函数,若找到则返回x的位置,没找到则返回npos。npos代表no postion,表示没找到,其值为-1

    #include <iostream>
    using namespace std;
    
    int main()
    {
        string s = "abcdefg";
        int x = s.find("abc");
        int y = s.find("ddd");
        cout << x << endl;
        cout << y << endl;
        
        return 0;
    }
    

    运行结果:

    0
    -1
    

    (3)substr(x, y)

    basic_string substr(size_type  _Off = 0,size_type _Count = npos) const;
    

    参数
    _Off:所需的子字符串的起始位置。默认值为0.
    _Count:复制的字符数目。如果没有指定长度_Count或_Count+_Off超出了源字符串的长度,则子字符串将延续到源字符串的结尾。

    返回值
    一个子字符串,从其指定的位置开始

    (4)C++字符串与C语言字符串之间的互相转化
    C++中有string类型,C语言中没有string类型。若要把C++中的string类型转化为C语言中的string类型,必须用c_str()函数。

    #include <iostream>
    using namespace std;
    
    int main()
    {
        string s = "hello";
        const char *s1 = s.c_str();
        cout << s1 << endl;
    
        return 0;
    }
    

    反过来,若C语言中的字符串要转化为C++中的string类型,直接赋值即可

    #include <iostream>
    using namespace std;
    
    int main()
    {
        const char *a = "Hi";
        string s = a;
        cout << s << endl;
    
        return 0;
    }
    

    (5)atoi
    atoi为C语言中的字符串转化为整型的函数。若要转化C++中的字符串,要先用c_str()转化为C语言的字符串,才能使用atoi。
    atoi声明于<stdlib.h>或<cstdlib>中。

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    int main()
    {
        string s = "23";
        int a = atoi(s.c_str());
        cout << a << endl;
    
        return 0;
    }
    

    反过来,有个整型转换为字符串的函数叫itoa,这个不是标准函数,有些编译器不支持。

    二、split()实现

    令人遗憾的是,C++标准库STL中没有提供分割字符串的函数,所以只能自己实现一个。

    #include<iostream>
    #include<vector>
    #include<cstdlib>
    using namespace std;
    
    // 这里&是引用,不是取地址符
    vector<string> split(const string &s, const string &separator)
    {
        vector<string> v;
        
        string::size_type beginPos, sepPos;
        beginPos = 0;
        sepPos = s.find(separator);
        
        while(string::npos != sepPos)
        {
            v.push_back(s.substr(beginPos, sepPos - beginPos));
            beginPos = sepPos + separator.size();
            sepPos = s.find(separator, beginPos);
        }
    
        if(beginPos != s.length())
        {
            v.push_back(s.substr(beginPos));
        }
    
        return v;
    }
    
    int main()
    {
        string s = "1 22 333";
        // 因为参数separator是string类型,所以这里只能用" ",不能用' '
        vector<string> vec = split(s, " ");
        vector<string>::iterator it;
        for(it = vec.begin(); it != vec.end(); it++)
        {
            // 输出字符串
            cout << (*it) << endl;
            // 输出整数
            cout << atoi((*it).c_str()) << endl;
        }
    }
    

    运行结果:

    1
    1
    22
    22
    333
    333

    两数交换

    两个数相等的交换情况。

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    // 两个参数是指针(指向地址的引用)
    void myswap(int *x, int *y)
    {
        *x ^= *y;
        *y ^= *x;
        *x ^= *y;
    }
    
    // 两个参数是引用,在这里&代表引用,不代表地址
    void myswap2(int &x, int &y)
    {
        x ^= y;
        y ^= x;
        x ^= y;
    }
    
    int main()
    {
        cout << "**********交换不同的值**********" << endl;
        int a = 1, b = 2;
        myswap(&a, &b); // 因为myswap的参数是指针,所以必须传地址
        cout << a << ' ' << b << endl;
    
        int a2 = 3, b2 = 4;
        myswap2(a2, b2);
        cout << a2 << ' ' << b2 << endl;
    
        cout << "**********交换相同的值**********" << endl;
        int a3 = 5, b3 = 5;
        myswap(&a3, &b3); // 因为myswap的参数是指针,所以必须传地址
        cout << a3 << ' ' << b3 << endl;
    
        int a4 = 6, b4 = 6;
        myswap2(a4, b4);
        cout << a4 << ' ' << b4 << endl;
    
        int c[1];
        c[0] = 7;
        myswap(&c[0], &c[0]);
        cout << c[0] << ' ' << c[0] << endl;
    
        int d[1];
        d[0] = 8;
        myswap2(d[0], d[0]);
        cout <<d[0] << ' ' << d[0] << endl;
    
        int e[1];
        e[0] = 9;
        swap(e[0], e[0]);
        cout <<e[0] << ' ' << e[0] << endl;
    
        return 0;
    }
    

    运行结果:

    **********交换不同的值**********
    2 1
    4 3
    **********交换相同的值**********
    5 5
    6 6
    0 0
    0 0
    9 9
    

    结果显示,前两组数值不同的两个数,能交换成功。后五组相同的值,交换成功的有3组。不成功的有两组,并且值都变成了0。
    这是什么原因呢?
    观察最后三对的数,都是数组里的同一元素交换。myswap和myswap2函数是咱们自己定义的,swap函数是由<algorithm>提供的。可见自己写的两个函数,一定存在bug。

    仔细观察,发现a3 = 5, b3 = 5,这是两个不同的变量(在内存里的地址不同),而myswap2(d[0], d[0]),这是对同一个地址里的数交换。
    d0 = 8时,
    a = a ^ b = 8 ^ 8 = 0,因为a和b都指向d0,所以此时b = a = 0。
    b = b ^ a = 0 ^ 0 = 0,
    a = a ^ b = 0 ^ 0 = 0,
    所以最终得到的是0 0,而不是8 8。
    对于myswap(&c[0], &c[0]),与myswap2(d[0], d[0])的道理是一样的。

    改进:如果值一样,那就不用交换了:

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    // 两个参数是指针(指向地址的引用)
    void myswap(int *x, int *y)
    {
        if(x != y)
        {
            *x ^= *y;
            *y ^= *x;
            *x ^= *y;
        }
    }
    
    // 两个参数是引用,在这里&代表引用,不代表地址
    void myswap2(int &x, int &y)
    {
        if(x != y)
        {
            x ^= y;
            y ^= x;
            x ^= y;
        }
    }
    
    int main()
    {
        cout << "**********交换不同的值**********" << endl;
        int a = 1, b = 2;
        myswap(&a, &b); // 因为myswap的参数是指针,所以必须传地址
        cout << a << ' ' << b << endl;
    
        int a2 = 3, b2 = 4;
        myswap2(a2, b2);
        cout << a2 << ' ' << b2 << endl;
    
        cout << "**********交换相同的值**********" << endl;
        int a3 = 5, b3 = 5;
        myswap(&a3, &b3); // 因为myswap的参数是指针,所以必须传地址
        cout << a3 << ' ' << b3 << endl;
    
        int a4 = 6, b4 = 6;
        myswap2(a4, b4);
        cout << a4 << ' ' << b4 << endl;
    
        int c[1];
        c[0] = 7;
        myswap(&c[0], &c[0]);
        cout << c[0] << ' ' << c[0] << endl;
    
        int d[1];
        d[0] = 8;
        myswap2(d[0], d[0]);
        cout <<d[0] << ' ' << d[0] << endl;
    
        int e[1];
        e[0] = 9;
        swap(e[0], e[0]);
        cout <<e[0] << ' ' << e[0] << endl;
    
        return 0;
    }
    

    运行结果:

    **********交换不同的值**********
    2 1
    4 3
    **********交换相同的值**********
    5 5
    6 6
    7 7
    8 8
    9 9
    

    现在结果对了。在此,咱们可以进一步推断<algorithm>中的swap函数的实现方式:
    (1)参数是用引用而不是用指针,因为调用方式 是swap(e[0], e[0])而不是swap(&e[0], &e[0])
    (2)swap内部用if作了判断。



  • 相关阅读:
    NOIP 2011 提高组 计算系数(vijos 1739)(方法:二项式定理)
    NOIP 2012 提高组 借教室(vijos 1782) 总览
    NOIP 2012 提高组 借教室(vijos 1782) 线段树85分打法
    NOIP 2011 提高组 铺地毯(vijos 1736)(方法:纯枚举)
    获取指定时间的前一天、后一天及当前时间的前一周、前一个月
    input file禁用手机本地文件选择,只允许拍照上传图片
    给定一个时间,获取该时间所在周的周一及周日
    Fiddler手机抓包软件简单使用将h5效果显示在手机
    解决Linux服务器更换IP后,ssh连接被拒绝问题
    解决Hadoop启动报错:File /opt/hadoop/tmp/mapred/system/jobtracker.info could only be replicated to 0 nodes, instead of 1
  • 原文地址:https://www.cnblogs.com/alan-blog-TsingHua/p/9607661.html
Copyright © 2020-2023  润新知