学习算法的时候,其中一道经典就是大整数乘法咯,感觉有点难理解,于是写一篇博客加深下理解。
大数相乘不可以直接得到答案,肯定会超出数的范围,而解决大数相乘的办法就是分治法:将大问题变成小问题,再变成简单问题,最后进行合并。
例如:
继续分治可得:
……
最后合并相加就可以得到结果
4 |
3 |
2 |
1 |
6 |
5 |
4 |
3 |
2 |
代码如下:
#include
#include
#include
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;iS[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->cc)
{
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;ic;i++)
{
if(iS[i-k];//补零结束,开始取数
if(il)
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;il;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:"<>sa;
cout<<"输入大整数b:"<>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<<"最终的结果:"<=0;i--)
cout<