算法06:大整数乘法分治算法——分治法Part2

(2)大整数乘法

一般我们用int、long来定义整数,但是超过了这些范围的大整数如“123456789”我们怎么表示呢,大整数的加减乘除怎么又如何计算呢?

两个n位整数a,b相乘,一般有一下几种方法:

1.用小学的竖式运算,要用到两层for循环,时间复杂度是O(n^2)

2.用分治法,把整数拆分成两部分,一般是对称拆分

  a = a1* 10^(n/2)+a0    b = b1* 10^(n/2)+b0
  a*b = a1*b1*10^n +(a1*b0*+a0*b1)*10^(n/2)+a0*b0

  拆分后需要对n/2位数做四次乘法运算,时间复杂度可表示为

   n =1   T(n) = O(1)         

   n>1    T(n) = 4T(n/2) +O(n)

   计算以后时间复杂度还是O(n^2)

3.还需要减少乘法的次数

   (1)    a1*b0*+a0*b1 = (a1+a0)*(b1+b0)-a1*b1-a0*b0

   (2)    a1*b0*+a0*b1 = (a1-a0)*(b0-b1)+a1*b1+a0*b0

   简化后需要对n/2位数做三次乘法运算,时间复杂度可表示为

    n =1   T(n) = O(1)         

    n>1    T(n) = 3T(n/2) +O(n)

    计算以后时间复杂度是O(n^log3)=O(n^1.59),(1)中两数相加可能会得到m+1位的结果,增加了复杂度,所以选第二种方案。

具体算法:

1.大整数可以用字符数组、int数组以及字符串来表示;

2.对于位数不相同的大整数乘法,用上面的第2种方法比较简单,a*b = a1*b1*10^n +(a1*b0*+a0*b1)*10^(n/2)+a0*b0,其中的几个乘法又可以考虑用拆分的方法递归求解;

3.计算乘积的递归函数终止条件是两个乘数的位数都为1,这时可直接返回相乘结果;

string mutiply(string& a, string& b)
{
     int num1 = atol(a.c_str());
     int num2 = atol(b.c_str());

     stringstream ss;
     string s;
     ss << num1*num2;
     ss >> s;
     
     return s;
}

if(a.length() ==1 || b.length() == 1)
        return mutiply(a, b);

4.如果没有达到递归的终止条件,就继续拆分算出各部分乘积再相加

string bigInt_mutiply(string& a, string& b)
{
     if(a.length() ==1 || b.length() == 1)
        return mutiply(a, b);
     
     else{
       string a1 = a.substr(0, a.length()/2);
       string a0 = a.substr(a1.length());
       string b1 = b.substr(0, b.length()/2);
       string b0 = b.substr(b1.length());
         
       string c0 = bigInt_mutiply(a0, b0);
       string c1 = bigInt_mutiply(a1, b0);
       string c2 = bigInt_mutiply(a0, b1);
       string c3 = bigInt_mutiply(a1, b1);
       
       c3 = add_zero(c3, a0.length()+b0.length());
       c2 = add_zero(c2, b0.length());
       c1 = add_zero(c1, a0.length());
      
       add(c3, c2);
       add(c3, c1);
       add(c3, c0);

       return  c3;
     }          
}

//返回两个数相加的字符串结果 
string add(string& a, string& b)
{
       int len1 = a.length(), len2 = b.length(), i, j;
       
       //a>=b 
       if(len1 < len2){
          string t = a;
          a = b;
          b = t;
          int t0 = len1;
          len1 = len2;
          len2 = t0; 
       }
    
       for(i = len1-1, j = len2-1;i >= 0, j >= 0; i--, j--){
           int t = a[i] - '0' + b[j] - '0' ;
            
           if(t >= 10){
              a[i] = t - 10 + '0';
           
              if(i > 0){
                 a[i-1] = a[i-1] + 1;
              }else{
                 a = '1' + a;
              }
             
           }else{
             a[i] = t + '0';
           }
       }
       
       if(i >= 0){
            for(j = i; j>= 0; j--){
                if(a[j] >= 58){
                   a[j] = a[j] - 10;
           
                   if(j > 0){
                     a[j-1] = a[j-1] + 1;
                   }else{
                     a = '1' + a;
                   }
                }
             
             }
       }
       
       return a;
}

//在字符串的右边加0 
string add_zero(string& a, int len)
{     
       for(int i = 0; i < len; i++)
           a = a + '0';
           
       return a; 
}

完整程序:

#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

//返回两个数相乘的字符串结果 
string mutiply(string& a, string& b)
{
     int num1 = atol(a.c_str());
     int num2 = atol(b.c_str());

     stringstream ss;
     string s;
     ss << num1*num2;
     ss >> s;
     
     return s;
}

//返回两个数相加的字符串结果 
string add(string& a, string& b)
{
       int len1 = a.length(), len2 = b.length(), i, j;
       
       //a>=b 
       if(len1 < len2){
          string t = a;
          a = b;
          b = t;
          int t0 = len1;
          len1 = len2;
          len2 = t0; 
       }
    
       for(i = len1-1, j = len2-1;i >= 0, j >= 0; i--, j--){
           int t = a[i] - '0' + b[j] - '0' ;
            
           if(t >= 10){
              a[i] = t - 10 + '0';
           
              if(i > 0){
                 a[i-1] = a[i-1] + 1;
              }else{
                 a = '1' + a;
              }
             
           }else{
             a[i] = t + '0';
           }
       }
       
       if(i >= 0){
            for(j = i; j>= 0; j--){
                if(a[j] >= 58){
                   a[j] = a[j] - 10;
           
                   if(j > 0){
                     a[j-1] = a[j-1] + 1;
                   }else{
                     a = '1' + a;
                   }
                }
             
             }
       }
       
       return a;
}

//在字符串的右边加0 
string add_zero(string& a, int len)
{     
       for(int i = 0; i < len; i++)
           a = a + '0';
           
       return a; 
}

/*递归计算大整数乘积 
a = a1* 10^a0.length()+a0
b = b1* 10^b0.length()+b0
a*b = a1*b1*10^(a0.length()+b0.length())
    +a1*b0*10^a0.length()+a0*b1*10^b0.length()+a0*b0
*/ 
string bigInt_mutiply(string& a, string& b)
{
     if(a.length() ==1 || b.length() == 1)
        return mutiply(a, b);
     
     else{
       string a1 = a.substr(0, a.length()/2);
       string a0 = a.substr(a1.length());
       string b1 = b.substr(0, b.length()/2);
       string b0 = b.substr(b1.length());
         
       string c0 = bigInt_mutiply(a0, b0);
       string c1 = bigInt_mutiply(a1, b0);
       string c2 = bigInt_mutiply(a0, b1);
       string c3 = bigInt_mutiply(a1, b1);
       
       c3 = add_zero(c3, a0.length()+b0.length());
       c2 = add_zero(c2, b0.length());
       c1 = add_zero(c1, a0.length());
      
       add(c3, c2);
       add(c3, c1);
       add(c3, c0);

       return  c3;
     }          
}

int main()
{ 
    string a, b;
    while(cin>>a>>b){
         cout<<bigInt_mutiply(a, b)<<endl;
    }
     
    system("PAUSE");
    return 0;
}

    原文作者:大整数乘法问题
    原文地址: https://blog.csdn.net/wenyijiao/article/details/24111887
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞