zoukankan      html  css  js  c++  java
  • 转 大整数乘法 1 复杂度分析

    题目:设X和Y都是n位的十进制整数,计算它们的乘积XY。

    分析:

    我们可以用小学所学的方法来设计一个计算乘积XY的算法,但是这样做计算步骤太多,显得效率较低。如果将每2个1位数的乘法或加法看作一步运算,那么这种方法要作O(n2)步运算才能求出乘积XY。下面我们用分治法来设计一个更有效的大整数乘积算法。将n位的二进制整数X和Y各分为2段,每段的长为n/2位(为简单起见,假设n是2的幂),如图所示。

     

                          

                                        图: 大整数X和Y的分段

    由此,

    X=A*10^(n/2)+B ,Y=C*10^(n/2)+D。

    这样,X和Y的乘积为:

     

    XY=[A*10^(n/2)+B][C*10^(n/2)+D]=AC*10^n+(AD+CB)*10^(n/2)+BD  (1)

     

    如果按式(1)计算XY,则我们必须进行4次n/2位整数的乘法(AC,AD,BC和BD),以及3次不超过n位的整数加法(分别对应于式(1)中的加号),此外还要做2次移位(分别对应于式(1)中乘2n和乘2n/2)。所有这些加法和移位共用O(n)步运算。设T(n)是2个n位整数相乘所需的运算总数,则由式(1),我们有:

          

    由此可得T(n)=O(n2)。因此,用(1)式来计算X和Y的乘积并不比小学生的方法更有效。要想改进算法的计算复杂性,必须减少乘法次数。为此我们把XY写成另一种形式:

    XY=AC*10n+[(A-B)(D-C)+AC+BD]*10n/2+BD                     (3)

    虽然,式(3)看起来比式(1)复杂些,但它仅需做3次n/2位整数的乘法(AC,BD和(A-B)(D-C)),6次加、减法和2次移位。由此可得:

     

    用解递归方程的套用公式法马上可得其解为T(n)=O(nlog3)=O(n1.59)。利用式(3),可写出相应的代码:

    66算法分析

     

    由公式(3)可以看出,我们需要完成以下功能:

    1> 大整数的加法

    2> 大整数的减法

    3> 大整数的乘法

    利用分治法在计算大整数的过程,当某个中间值在int所表示的范围内时,可直接用整数的加减乘运算进行计算(同时必须保证进行这种运算的结果也在int所标示的范围内),加快计算速度。

    代码:

      1: #include<iostream>
    
    
      2: #include<vector>
    
    
      3: using namespace std ;
    
    
      4: void sub(const vector<char>& x, const vector<char>& y, vector<char>& ret) ; 
    
    
      5: void add(const vector<char>& x, const vector<char>& y, vector<char>& ret) ; 
    
      6: // int(0,1,2...9) to char
    
      7: void itoa(const int i, char&ch) 
    
    
      8: {
    
    
      9:     if (i >= 0 && i <= 9){
    
    
     10:         ch = '0' + i ;
    
    
     11:     }else{
    
    
     12:         ch=' ' ;
    
    
     13:     }
    
    
     14: }
    
     15: //char to int 
    
    
     16: int atoi(const char ch)
    
    
     17: {
    
    
     18:     if(ch>='0' && ch <='9')
    
    
     19:     {
    
    
     20:         return (ch - '0') ;
    
    
     21:     }else{
    
    
     22:         return -1 ;
    
    
     23:     }
    
    
     24: }
    
     25: // string to int
    
    
     26: int str2int(vector<char> str)
    
    
     27: {
    
    
     28:     int ret = 0 ; 
    
    
     29:     for(int i=0;i<str.size();++i){
    
    
     30:         ret *= 10 ;
    
    
     31:         ret += atoi(str[i]) ;
    
    
     32:     } 
    
    
     33:     return ret ;
    
    
     34: }
    
     35: // int to string
    
    
     36: void int2str(int i,vector<char>& vCh)
    
    
     37: {
    
    
     38:     int tmp = i ;
    
    
     39:     int j = 0 ;
    
    
     40:     char ch ;
    
    
     41:     int sign = 1 ;
    
    
     42:     if (tmp<0){
    
    
     43:         sign = -1 ;
    
    
     44:         tmp *= -1 ;
    
    
     45:     }
    
    
     46:     while(tmp){
    
    
     47:         j = tmp % 10 ;    
    
    
     48:         tmp /= 10 ;
    
    
     49:         itoa(j,ch) ;
    
    
     50:         vCh.insert(vCh.begin(),ch) ;
    
    
     51:     }
    
    
     52:     if (sign==-1){
    
    
     53:         vCh.insert(vCh.begin(),'-') ;
    
    
     54:     }
    
    
     55: }
    
     56: //compare the two big int num in the format of string
    
    
     57: int compare(const vector<char>& x, const vector<char>& y) 
    
    
     58: {
    
    
     59:     char signX ,signY ;
    
    
     60:     signX = x.front() ;
    
    
     61:     signY = y.front() ;
    
    
     62:     if ('-' == signX && '-' != signY){          // x<0,y>0
    
    
     63:         return 1 ;
    
    
     64:     }else if ('-' != signX && '-' == signY){    // x>0 ,y<0
    
    
     65:         return -1 ;
    
    
     66:     }else if ('-' == signX && '-' == signY){    // x<0 ,y<0
    
    
     67:         vector<char> X(x.begin(),x.end()) ;     // tmp var
    
    
     68:         vector<char> Y(y.begin(),y.end()) ;
    
    
     69:         X.erase(X.begin()) ;
    
    
     70:         Y.erase(Y.begin()) ;
    
    
     71:         return (-1) * compare(X,Y) ;
    
    
     72:     }else{                                      // x>0 , y>0
    
    
     73:         if (x.size()>y.size()){                 // x is longer
    
    
     74:             return -1 ;
    
    
     75:         }else if (x.size()<y.size()) {          // y is longer
    
    
     76:             return 1 ;
    
    
     77:         }else {                                 // x.szie() == y.size()          
    
    
     78:             int i=0 ;
    
    
     79:             for (i=0;i<x.size();++i){
    
    
     80:                 if (x[i]<y[i]){
    
    
     81:                     return 1 ;
    
    
     82:                 }else if (x[i]>y[i]){
    
    
     83:                     return -1 ;
    
    
     84:                 }else{                          // x[i] == y[i]
    
    
     85:                     continue ;
    
    
     86:                 }
    
    
     87:             }
    
    
     88:             if (-1==i){                         // x == y
    
    
     89:                 return 0 ;
    
    
     90:             }
    
    
     91:         }
    
    
     92:     }
    
    
     93: }
    
     94: //if x < y return true ,else false
    
    
     95: bool Less(const vector<char>& x, const vector<char>& y)
    
    
     96: { 
    
    
     97:     return (1==compare(x,y)) ;    
    
    
     98: }
    
     99: //if x > y return true, else false
    
    
    100: bool Great(const vector<char>& x, const vector<char>& y)
    
    
    101: {
    
    
    102:     return (-1==compare(x,y)) ;
    
    
    103: }
    
    104: // if x==y return true ,else false
    
    
    105: bool equal(const vector<char>& x, const vector<char>& y) 
    
    
    106: {
    
    
    107:     return (0==compare(x,y)) ;
    
    
    108: }
    
    109: // x*10^n ==> add n '0' at the end of the string
    
    
    110: void shiftLeft(vector<char>&x, const int n)
    
    
    111: {
    
    
    112:     for(int i=0;i<n;++i){
    
    
    113:         x.push_back('0') ;
    
    
    114:     }
    
    
    115: }
    
    116: // del the '0' at the begining of the string
    
    
    117: int delFirstZero(vector<char>&x) 
    
    
    118: {
    
    
    119:     vector<char>::iterator it ;
    
    
    120:     int i ;
    
    
    121:     for(i=0;i<x.size();++i){
    
    
    122:         if ('0'!=x[i]){
    
    
    123:             break ;
    
    
    124:         }
    
    
    125:     }
    
    
    126:     if (i>0){
    
    
    127:         it = x.begin() ;
    
    
    128:         x.erase(it,it+i) ;
    
    
    129:     }
    
    
    130: }
    
    131: // add some '0' at the begining of x or y
    
    132: // so the value of x and y is not changed 
    
    133: // let x.size() == y.size()
    
    
    134: int adjustSize(vector<char>& x,vector<char>& y) 
    
    
    135: {
    
    
    136:     delFirstZero(x) ;
    
    
    137:     delFirstZero(y) ;
    
    
    138:     //second add 0 at the front
    
    
    139:     int n1 = x.size() ;
    
    
    140:     int n2 = y.size() ;
    
    
    141:     int n = n1 ;
    
    
    142:     if (n1<n2){
    
    
    143:         n = n2 ;
    
    
    144:     }
    
    
    145:     n = (n%2==0?n:n+1) ;  // n is a even  num
    
    
    146:     n = (n>0?n:1) ;       // n at least is 1
    
    
    147:     if (n1 != n2){
    
    
    148:         for (int i=0;i<n-n1;++i){
    
    
    149:             x.insert(x.begin(),'0') ;
    
    
    150:         }
    
    
    151:         for (int i=0;i<n-n2;++i){
    
    
    152:             y.insert(y.begin(),'0') ;
    
    
    153:         }      
    
    
    154:     } 
    
    
    155:     return n ;
    
    
    156: }
    
    
    157: // add the big int num 
    
    
    158: void add(const vector<char>& X, const vector<char>& Y, vector<char>& ret)
    
    
    159: {
    
    
    160:     int a,b,c,r ;
    
    
    161:     char ch ;
    
    
    162:     vector<char> x(X.begin(),X.end()) ;
    
    
    163:     vector<char> y(Y.begin(),Y.end()) ;
    
    
    164:     // delete the 0 in the front of the num
    
    
    165:     delFirstZero(x) ;
    
    
    166:     delFirstZero(y) ;        
    
    
    167: 
    
    
    168:     ret.clear() ;
    
    
    169:     if (x.empty()){         // x empty
    
    
    170:         if(y.empty()){      // x and y is empty
    
    
    171:             ret.push_back('0') ;
    
    
    172:         }else{              // x is empty ,y is not empty
    
    
    173:             ret.insert(ret.begin(),y.begin(),y.end()) ;
    
    
    174:         }
    
    
    175:         return ;
    
    
    176:     }
    
    
    177:     if (y.empty()){   // y is empty and x is not empty
    
    
    178:         ret.insert(ret.begin(),x.begin(),x.end()) ;
    
    
    179:         return ;
    
    
    180:     }
    
    
    181: 
    
    
    182:     vector<char> zero(1,'0') ;
    
    
    183:     if(Less(x,zero) && Less(y,zero)){            // x<0,y<0
    
    
    184:         x.erase(x.begin()) ;
    
    
    185:         y.erase(y.begin()) ;
    
    
    186:         add(x,y,ret) ;
    
    
    187:         ret.insert(ret.begin(),'-') ;
    
    
    188:         return ;
    
    
    189:     } else if (Less(x,zero) && Great(y,zero)){    // x<0,y>0
    
    
    190:         x.erase(x.begin()) ;
    
    
    191:         sub(y,x,ret) ;
    
    
    192:         return ;
    
    
    193:     } else if (Great(x,zero)&& Less(y,zero)){     // x>0,y<0
    
    
    194:         y.erase(y.begin()) ;
    
    
    195:         sub(x,y,ret) ;
    
    
    196:         return ;
    
    
    197:     }else{                                         // x>0,y>0     
    
    
    198:         // for optimization
    
    
    199:         if(x.size()<10 && y.size()<10){            //x,y < (2^31-1)/2
    
    
    200:             int tmpX = str2int(x) ;
    
    
    201:             int tmpY = str2int(y) ;
    
    
    202:             int tmpR = tmpX + tmpY ;
    
    
    203:             int2str(tmpR,ret) ;
    
    
    204:             return ;
    
    
    205:         }
    
    
    206:         adjustSize(x,y) ;                           
    
    
    207:         c = 0 ;
    
    
    208:         for (int i=x.size()-1;i>=0;--i){
    
    
    209:             a = atoi(x[i]) ;
    
    
    210:             b = atoi(y[i]) ;
    
    
    211:             r = a + b + c ;
    
    
    212:             c = r / 10 ;                                // carry, c==0 or c==1
    
    
    213:             itoa(r%10,ch) ;
    
    
    214:             if (' ' != ch){
    
    
    215:                 ret.insert(ret.begin(),ch) ;
    
    
    216:             }
    
    
    217:         }
    
    
    218:         if ( 1==c ){                                    // the last time add ,may carry
    
    
    219:             itoa(c,ch) ;
    
    
    220:             if (' ' != ch){
    
    
    221:                 ret.insert(ret.begin(),ch);
    
    
    222:             }
    
    
    223:         }
    
    
    224:     }
    
    
    225: }
    
    
    226: // sub two big int num
    
    
    227: void sub(const vector<char>& x,const vector<char>& y, vector<char>& ret)
    
    
    228: {
    
    
    229:     int a,b,c,r ;
    
    
    230:     char ch ;
    
    
    231:     ret.clear() ;
    
    
    232:     vector<char> X(x.begin(),x.end()) ;
    
    
    233:     vector<char> Y(y.begin(),y.end()) ;
    
    
    234:     delFirstZero(X) ;
    
    
    235:     delFirstZero(Y) ;      
    
    
    236:     if (X.empty()){         // x empty
    
    
    237:         if (Y.empty()){
    
    
    238:             ret.push_back('0') ;
    
    
    239:         }else{
    
    
    240:             ret.insert(ret.begin(),Y.begin(),Y.end()) ;
    
    
    241:         }
    
    
    242:         return ;
    
    
    243:     }
    
    
    244:     if (Y.empty()){  // Y is empty and X is not empty
    
    
    245:         ret.insert(ret.begin(),X.begin(),X.end()) ;
    
    
    246:         return ;
    
    
    247:     } 
    
    
    248: 
    
    
    249:     vector<char> zero(1,'0') ;
    
    
    250:     
    
    
    251:     if (equal(X,Y)){                            // x==y
    
    
    252:         ret.clear() ;
    
    
    253:         ret.push_back('0') ;
    
    
    254:         return ;
    
    
    255:     }
    
    
    256:     if (Less(X,zero) && Less(Y,zero)){         // x<0,y<0
    
    
    257:         Y.erase(Y.begin()) ;
    
    
    258:         X.erase(X.begin()) ;
    
    
    259:         return sub(Y,X,ret) ;
    
    
    260:     }else if (Less(X,zero) && Great(Y,zero)){   // x<0,y>0
    
    
    261:         Y.insert(Y.begin(),'-') ;
    
    
    262:         return add(X,Y,ret) ;
    
    
    263:     }else if (Great(X,zero) && Less(Y,zero)){   // x>0,y<0
    
    
    264:         Y.erase(Y.begin()) ;
    
    
    265:         return add(X,Y,ret) ;
    
    
    266:     }else{                                      // x>=0,y>=0
    
    
    267:         if (Less(X,Y)){                         // x < y
    
    
    268:             sub(Y,X,ret) ;
    
    
    269:             delFirstZero(ret) ;
    
    
    270:             ret.insert(ret.begin(),'-') ;
    
    
    271:             return ; 
    
    
    272:         }
    
    
    273:         // for optimization
    
    
    274:         if(x.size()<10 && y.size()<10){            //x,y < (2^31-1)
    
    
    275:             int tmpX = str2int(x) ;
    
    
    276:             int tmpY = str2int(y) ;
    
    
    277:             int tmpR = tmpX - tmpY ;
    
    
    278:             int2str(tmpR,ret) ;
    
    
    279:             return ;
    
    
    280:         }              
    
    
    281:         adjustSize(X,Y) ;                       // x > y
    
    
    282:         for (int i=X.size()-1;i>=0;--i){                  // from low to high
    
    
    283:             a = atoi(X[i]) ;
    
    
    284:             b = atoi(Y[i]) ;
    
    
    285:             r = a - b ;
    
    
    286:             if (r<0){                           // borrow 1 from the high bit 
    
    
    287:                 int j=i-1 ;
    
    
    288:                 for (;j>=0;--j){
    
    
    289:                     if ('0' != X[j]){
    
    
    290:                         c = atoi(X[j]) ;
    
    
    291:                         --c ;
    
    
    292:                         itoa(c,ch) ;
    
    
    293:                         if (' ' != ch){
    
    
    294:                             X[j] = ch ;
    
    
    295:                         }
    
    
    296:                         break ;
    
    
    297:                     }else{// x[j] == 0 then set it to 9
    
    
    298:                         itoa(9,ch) ;
    
    
    299:                         if (' ' != ch){
    
    
    300:                             X[j] = ch ;
    
    
    301:                         }
    
    
    302:                     }
    
    
    303:                 }
    
    
    304:                 r = r + 10 ;  // 0<r<10
    
    
    305:             }
    
    
    306:             itoa(r,ch) ;
    
    
    307:             if (' ' != ch){
    
    
    308:                 ret.insert(ret.begin(),ch) ;
    
    
    309:             }
    
    
    310:         }                    
    
    
    311:         delFirstZero(ret) ;
    
    
    312:         return  ;
    
    
    313:     }
    
    
    314: }
    
    
    315: // mul two big int num
    
    
    316: void mul(const vector<char>& X, const vector<char>& Y, vector<char>& result)
    
    
    317: {
    
    
    318:     int sign = 1 ;
    
    
    319: 
    
    
    320:     vector<char>x(X.begin(),X.end()) ;
    
    
    321:     vector<char>y(Y.begin(),Y.end()) ;
    
    
    322: 
    
    
    323:     delFirstZero(x) ;
    
    
    324:     delFirstZero(y) ;      
    
    
    325:     // any of the x,y is empty ,set ret to '0'
    
    
    326:     if (x.empty() || y.empty()){
    
    
    327:         result.clear() ;
    
    
    328:         result.push_back('0') ;
    
    
    329:         return ;
    
    
    330:     }
    
    
    331:     // get the sign of the result
    
    
    332:     if ('-' == x.front()){           // x is negative
    
    
    333:         sign *= -1 ;
    
    
    334:         x.erase(x.begin()) ;
    
    
    335:     }
    
    
    336:     if ('-' == y.front()){  //both x and y is negative 
    
    
    337:         sign *= -1 ;
    
    
    338:         y.erase(y.begin()) ;
    
    
    339:     }
    
    
    340: 
    
    
    341:     // the exit condition
    
    
    342: 
    
    
    343:     if (x.size()<=5 && y.size()<=5){
    
    
    344:         int a = str2int(x) ;
    
    
    345:         int b = str2int(y) ;
    
    
    346:         if (a<46340 && b< 46340){
    
    
    347:             result.clear() ;
    
    
    348:             int2str(a*b*sign,result) ;
    
    
    349:             return ;
    
    
    350:         }
    
    
    351:     }
    
    
    352: 
    
    
    353:     // adjust x,y , let the size of x and y is even
    
    
    354:     adjustSize(x,y) ;
    
    
    355: 
    
    
    356:     vector<char> A(x.begin(),x.begin()+x.size()/2) ;
    
    
    357:     vector<char> B(x.begin()+x.size()/2,x.end()) ;
    
    
    358:     vector<char> C(y.begin(),y.begin()+y.size()/2) ;
    
    
    359:     vector<char> D(y.begin()+y.size()/2,y.end()) ;
    
    
    360:     // result = A*C*10^n +[(A-B)*(D-C)+AC+BD]*10^(n/2)+BD
    
    
    361:     // declaration some tmp var for compute 
    
    
    362:     vector<char> AC ;    // A * C
    
    
    363:     vector<char> BD ;    // B * D
    
    
    364:     vector<char> ABDC ;  // (A-B) * (D-C)
    
    
    365:     vector<char> v1;        // AC*10^n
    
    
    366:     vector<char> v2 ;       // [(A-B)*(D-C)+AC+BD]*10^(n/2)
    
    
    367:     vector<char> v3 ;       // v3 = v1 + v2
    
    
    368:     vector<char> subAB ;    // A - B
    
    
    369:     vector<char> subDC ;    // D - C 
    
    
    370:     vector<char> add2 ;     // (A-B)*(D-C)+AC
    
    
    371:     vector<char> add3 ;     // (A-B)*(D-C)+AC+BD
    
    
    372: 
    
    
    373:     mul(A,C,AC) ;       
    
    
    374:     mul(B,D,BD) ;      
    
    
    375:     sub(A,B,subAB) ;
    
    
    376:     sub(D,C,subDC) ;
    
    
    377:     mul(subAB,subDC,ABDC) ;
    
    
    378:     add(ABDC,AC,add2) ;
    
    
    379:     add(add2,BD,add3) ;
    
    
    380:     
    
    381:     int size = x.size() ;
    
    
    382:     if (1==size%2){
    
    
    383:         ++size ;
    
    
    384:     }
    
    
    385:     shiftLeft(AC,size) ;  
    
    
    386:     shiftLeft(add3,size/2) ;
    
    
    387:    
    
    388:     add(AC,add3,v3) ;
    
    
    389:     add(v3,BD,result) ;
    
    
    390:    
    
    391:     delFirstZero(result) ;
    
    
    392:     if (-1==sign){
    
    
    393:         result.insert(result.begin(),'-') ;
    
    
    394:     }
    
    
    395: }
    
    
    396:
  • 相关阅读:
    List<T>的使用
    onclientclick和onclick区别
    IOS学习资料
    DataTable排序的一般方法
    jquery特效
    交叉表、行列转换和交叉查询经典
    sql截取查询
    DelPhi学习网站
    EasyDarwin开源云平台接入海康威视EasyCamera摄像机之快照获取与上传
    EasyDarwin开源云平台接入海康威视EasyCamera摄像机之快照获取与上传
  • 原文地址:https://www.cnblogs.com/titer1/p/2445422.html
Copyright © 2011-2022 走看看