程序员面试题精选100题<6>-大整数的乘法

题目:设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),可写出相应的代码:

由公式(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: 
posted @ 2012-03-21 21:37  Better-zyy  阅读(691)  评论(0编辑  收藏  举报