有趣算法之大整数乘法

大整数乘法

20200924

原文链接:https://www.cnblogs.com/little-kwy/archive/2017/09/30/7613642.html

 

1. 分治思想

分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。即一种分目标完成程序算法,简单问题可用二分法完成。

简而言之,分治,其实就是分而治之,将一个大问题划分成小问题,再将这些小问题不断再不断的划分,依次重复,直至分成可以解决的小问题。

 

分治法的重点是分析问题是否可以划分为规模较小的子问题,难点是如何划分以及划分之后如何将各个子问题的解合并成最终的解。这一般需要用到数学知识或者其他理论。如下图:
  有趣算法之大整数乘法_第1张图片

 

 

2. 大整数乘法

(理想状态下,即X与Y相同)

现假设我们有两个大整数 X,Y,分别设为x=1234,Y=5678,需要求两个数的乘积XY。按照小学所学的方法去计算乘积,需要的时间复杂度为O(n2),运算效率太低。我们这里试着采用分治思想,将n位X和Y都分为2段,每段长度为n/2位。如下图:

有趣算法之大整数乘法_第2张图片

注:我们这里取的大整数X、Y是在理想状态下,即X与Y的位数一致,且image.png

 

3. 问题分析

 

  1. 首先将X和Y分成A,B,C,D
  2. 此时将X和Y的乘积转化为(1)式,把问题转化为求解因式分解的值

在(1)式中,我们一共需要进行4次n/2的乘法(AC2次,AD、BC各一次)和3次加法,因而该算法的时间复杂度为:

有趣算法之大整数乘法_第3张图片

 

通过master定理可以求得有趣算法之大整数乘法_第4张图片,跟小学算法的时间复杂度没有区别。

但是我们再来看看,我们是否可以用加法来换取乘法?因为多一个加法操作,也是常数项,对时间复杂度没有影响,如果减少一个乘法则不同。

(1)式化为:

image.png

现在的时间复杂度为:有趣算法之大整数乘法_第5张图片,通过master定理求得有趣算法之大整数乘法_第6张图片

 

4. 代码实现

#include 

//using namespace std;

#define SIGN(A)((A>0)?1:-1)
int divideConquer(int X,int Y,int n){
    int sign=SIGN(X)*SIGN(Y);
    int x=abs(X);
    int y=abs(Y);
    if(x==0 || y==0){
        return 0;
    }else if(n==1){
        return sign*x*y;
    }else{
        int A=(int)x/pow(10,(int)(n/2));
        int B=x-A*pow(10,n/2);
        int C=(int)y/pow(10,(int)(n/2));
        int D=y-C*pow(10,n/2);
        int AC = divideConquer(A, C, n / 2);
        int BD = divideConquer(B, D, n / 2);
        int ABDC = divideConquer((A - B), (D - C), n / 2) + AC + BD;
        return sign * (AC * pow(10 , n) + ABDC * pow(10, (int)(n / 2)) + BD); 
    }
}

int main(int argc, char* argv[])
{
    int x, y, n;
    scanf("%d%d%d", &x, &y, &n);
    printf("x 和 y的乘积为:%d", divideConquer(x, y, n));
    return 0;
}

运行结果:

有趣算法之大整数乘法_第7张图片

你可能感兴趣的:(书中不求甚解,#,算法与数据结构)