分治法 大整數乘法
阿新 • • 發佈:2018-11-23
學習演算法的時候,其中一道經典就是大整數乘法咯,感覺有點難理解,於是寫一篇部落格加深下理解。
大數相乘不可以直接得到答案,肯定會超出數的範圍,而解決大數相乘的辦法就是分治法:將大問題變成小問題,再變成簡單問題,最後進行合併。
例如:
1234*23456
=(12*10^2+34)*(234*10^2+56)
=12*234*10^4+12*56*10^2+34*234*10^2+34*56
繼續分治可得:
12*234*10^4
=(1*10+2)*(23*10+4)*10^4
=(1*23*10^2+1*4*10+2*23*10+2*4)*10^4
同理: 12*56*10^2=(1*5*10^2+1*6*10+2*5*10+2*6)*10^2
34*234*10^2=(3*23*10^2+3*4*10+4*23*10+4*4)*10^2
34*56=3*5*10^2+3*6*10+4*5*10+4*6
……
最後合併相加就可以得到結果
a.l=4 a.S[] a.c=0
4 |
3 |
2 |
1 |
b.l=5 b.S[] b.c=0
6 |
5 |
4 |
3 |
2 |
分解1:
ah=12*10^2 al=34
bh=234*10^2 bl=56
四次運算:ah*bh ah*bl al*bh al*bl
遞迴呼叫求子問題 ah*bh ah*bl al*bh al*bl
……
如ah*bh遞迴:ah*bh 分為 ahh*bhh, ahh*bhl , ahl*bhh , ahl*bhl
知道a出現個位數計算結果,然後回撥,得到結果
程式碼如下:
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
char sa[1000];
char sb[1000];
typedef struct NODE
{
int S[100];//倒序儲存大數
int l;//大數的長度
int c;//大數的冪次
}Node,*pNode;
void cp(pNode src,pNode des,int st,int lp)
{
int i,j;
for(i=st,j=0;i<st+lp;i++)//從st位置開始取lp個數
des->S[j++]=src->S[i];
des->l=lp;
des->c=st+src->c;
}
void add(pNode pa,pNode pb,pNode ans)
{
int i,cc,k,palen,pblen,len;
int ta,tb;
pNode temp;
if(pa->c<pb->c)
{
temp=pa;
pa=pb;
pb=temp;
}
ans->c=pb->c;//結果的冪次為最小冪次
cc=0;
palen=pa->l+pa->c;
pblen=pb->l+pb->c;
if(palen>pblen)
len=palen;
else
len=pblen;
k=pa->c-pb->c;//k為a左側需要補的0的個數
for(i=0;i<len-ans->c;i++)
{
if(i<k)
ta=0;//補零
else
ta=pa->S[i-k];//補零結束,開始取數
if(i<pb->l)
tb=pb->S[i];//取數
else
tb=0;//右側補零
if(i>pa->l+k)
ta=0;//a數取完後補零
ans->S[i]=(ta+tb+cc)%10;
cc= (ta+tb+cc)/10;
}
if(cc)
ans->S[i++]=cc;
ans->l=i;
}
void mul(pNode pa,pNode pb,pNode ans)
{
int i,cc;
int ma=pa->l/2;
int mb=pb->l/2;//分解
Node ah,al,bh,bl;//ah為大數的高位,al為低位
Node t1,t2,t3,t4,tmp;
pNode temp;
if(!ma || !mb)//即ma=0,a的長度為1
{
if(!ma)//保證a的長度大於等於b ,此時a為一位數
{
temp=pa;
pa=pb;
pb=temp;
}
ans->c=pa->c+pb->c;//結果冪次等於兩冪次之和
int w=pb->S[0];
cc=0;//初始化進位為0
for(i=0;i<pa->l;i++)
{
ans->S[i]=(w*pa->S[i]+cc)%10;
cc=(w*pa->S[i]+cc)/10;//進位
}
if(cc)
ans->S[i++]=cc;//最後有進位則再進一位
ans->l=i;
return;
}
//分解為四部分
cp(pa,&ah,ma,pa->l-ma);
cp(pa,&al,0,ma);
cp(pb,&bh,mb,pb->l-mb);
cp(pb,&bl,0,mb);
//四部分相乘
mul(&ah,&bh,&t1);
mul(&ah,&bl,&t2);
mul(&al,&bh,&t3);
mul(&al,&bl,&t4);
//四部分相加
add(&t3,&t4,ans);
add(&t2,ans,&tmp);
add(&t1,&tmp,ans);
}
int main()
{
Node ans,a,b;
cout<<"輸入大整數a:"<<endl;
cin>>sa;
cout<<"輸入大整數b:"<<endl;
cin>>sb;
a.l=strlen(sa);
b.l=strlen(sb);
int z=0,i;
//化為int形
for(i=a.l-1;i>=0;i--)
a.S[z++]=sa[i]-'0';
z=0;
a.c=0;
for(i=b.l-1;i>=0;i--)
b.S[z++]=sb[i]-'0';
b.c=0;
mul(&a,&b,&ans);
cout<<"最終的結果:"<<endl;
for(i=ans.l-1;i>=0;i--)
cout<<ans.S[i];
cout<<endl;
return 0;
}