问题描述:假设有两个大整数X、Y,现在要求X*Y的乘积
简介:大整数乘法是一种运算数学中的一种算法,将大整数式子分解为若干个整数表达式,使之可以通过乘法解决
算法设计思想:
①理想状态:当X、Y的位数相同时:
现在要求X*Y的乘积,小学的算法就是把X与Y中的每一项去乘,但是这样的乘法所需的时间复杂度为O(N^2),(因为每一位要逐个去乘),所以效率比较低下。那我们可以采用分治的算法,将X、Y拆分成四部分,如下图:
则X可表示为:X=A*10^(n/2)+B 同理Y也可以表示出来:Y=C*10^(n/2)+D
所以将一个大的整数分成两部分,问题规模减小,直接相乘就可以写成:
但是如果直接算AD+BC,效率太低(需要计算4次n/2位整数的乘法,以及三次加法),所以对·AD+BC进行分解优化后得:
计算成本:3次n/2位乘法,6次不超过n位加减法,2次移位,所有加法和移位共计O(n)次运算。由此可得:
②非理想状态:X、Y的位数不相同
依然采用分治的算法,将X、Y分别拆分为A与B、C与D,如下图:
计算成本:需要进行2次xn0的乘法(AC、AD各一次)、2次yn0的乘法(AC、BC各一次)和3次加法,因而该算法的时间复杂度为
对AD+BC进行分解优化 :
得到时间复杂度:T(m+n)=O(nlog3)=O(n1.59)
源代码展示(练习不靠谱版):
package MultiplicationOfLargeIntegers;
import java.util.Scanner;
public class multiplicationOfLargeIntegers {
public static void main(String args[])
{
Scanner in=new Scanner(System.in);
System.out.println("请输入x值:");
long x=in.nextInt();
long n=0;
long temp1=x;
while(temp1!=0) {
n++;
temp1=temp1/10;
}//计算整型长度
System.out.println("请输入y值:");
long y=in.nextInt();
long m=0;
long temp2=y;
while(temp2!=0) {
m++;
temp2=temp2/10;
}
long result=multiplication(x,y,n,m);
System.out.println("x*y的值是:"+result);
in.close();
}
public static long multiplication(long a,long b,long n,long m)
{
long s;//符号
if((a>0&&b>0)||(a<0&&b<0))
{
s=1;
}
else {
s=-1;
}
a=Math.abs(a); //不考虑符号
b=Math.abs(b);
if(n==0 || m==0)//递归出口
{
return 0;
}
else if(n==1 || m==1)//当a,b中只有一位数时
{
return s*a*b;
}
else{
long n1=n/2;//a的低半位数
long n2=n-n/2;//a的高半位数
long m1=m/2;//b的低半位数
long m2=m-m/2;//b的高半位数
long A= a/(int)(Math.pow(10, n1)); //高半位数值
long B=a%(int)(Math.pow(10, n1));//低半位数值
long C=b/(int)(Math.pow(10, m1));//pow支持的数据类型为double,所以在pow函数前加上(long)
long D=b%(int)(Math.pow(10, m1));
long AC=multiplication(A,C,n2,m2);
long BD=multiplication(B,D,n1,m1);
long ABCD=multiplication(A*(long)(Math.pow(10, n1))-B,D-C*(long)(Math.pow(10, m1)),n1,m1);
return s*(2*AC*(int)(Math.pow(10,n1+m1))+ABCD+2*BD);
}
}
}
个人练习归纳习惯,欢迎大家讨论反馈!