分治法 大整数乘法

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

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

例如:

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

 

分治法是一种算法设计策略,通过将问题分解成更小的子问题,再通过将解合并起来来解决原始问题。在大整数乘法问题中,可以使用分治法来提高算法效率。 下面是一个使用C语言编写的分治法大整数乘法的代码示例: #include <stdio.h> #include <math.h> long long int power(int a, int b) { if (b == 0) { return 1; } else { return a * power(a, b - 1); } } long long int multiply(long long int x, long long int y) { int n; if (x < 10 || y < 10) { return x * y; } n = fmax(log10(x) + 1, log10(y) + 1); int m = ceil(n / 2.0); long long int a = x / power(10, m); long long int b = x % power(10, m); long long int c = y / power(10, m); long long int d = y % power(10, m); long long int ac = multiply(a, c); long long int bd = multiply(b, d); long long int ad_bc = multiply(a + b, c + d) - ac - bd; return ac * power(10, 2 * m) + ad_bc * power(10, m) + bd; } int main() { long long int x, y; printf("请输入两个整数:"); scanf("%lld %lld", &x, &y); long long int result = multiply(x, y); printf("两数乘积为:%lld\n", result); return 0; } 在这个代码示例中,使用了递归来实现分治法的思想。首先判断输入的两个数是否小于10,如果是,则直接返回乘积。如果不是,则计算出这两个数的位数n,然后取n的一半向上取整得到m。分别将两个数的高位和低位等分为a、b、c、d四部分。 接着,使用递归调用multiply函数来计算ac、bd和ad_bc三个结果,最后将这三个结果按照指定的规则相加得到最终的乘积。 通过使用分治法,可以显著提高大整数乘法的效率。因为将问题分解成更小的子问题,每个子问题处理的数据规模更小,计算量相对减少,从而提高了算法的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值