分治法 大整数乘法

学习算法的时候,其中一道经典就是大整数乘法咯,感觉有点难理解,于是写一篇博客加深下理解。

大数相乘不可以直接得到答案,肯定会超出数的范围,而解决大数相乘的办法就是分治法:将大问题变成小问题,再变成简单问题,最后进行合并。

例如:

                          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;
}
 

 

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