遇到这样一道算法题:
题目
计算两个非负整数 A,,B 的乘积,A,B 可能会很大;
输入
第一行输入一个非负整数 A。
第二行输入一个非负整数 B。
A,B 的长度不大于 500。
输出格式
输出A * B的值
分析:
题目的要求是两位500位以内的整数相乘,所以根据现有的数据类型,无法直接算出答案,需要另寻它径。初步分析,考虑最极限的情况,可以经过推理得到:比如2个两位数相乘产生的最大的数为4位;两个3位数相乘的最大结果为6位;两个4位数相乘的最大值是8位....;因此两位500位的数相乘之后所能产生的最大的数是1000位;因此,分析到这里,我们就需要用一个长度为1000的数组和两个长度为500得数组来保存结果和输入值。
此外,分析乘法的运算,之前已经提过,利用现有的数据类型无法直接得出答案。所以我们分析乘法的具体步骤。回想起之前学过的计算机组成原理的上机实验,在机器底层的加减乘除法,都是一位一位操作,然后通过位移的方式来循环判断,直至运算结束。所以这里我直接套路了之前的用法,用最原始的方法(就是笔算的方法),一位乘以一位的操作计算机可以帮我们完成。因此我们可以假设一波,比如计算:12344321 * 1999123,首先我们是用第二个数的末尾数字去乘第一个数,挨个乘每一位,遇到进位要加进位;也就是12344321 * 3,然后又是倒数第二个数乘以第一个数:12344321 * 1 ......;通过循环往复,最后把第二个数字的第一位乘以第一个数就完成了第一步。第二步,我们需要将之前乘法得到的数做加法,并且每次加法都要错位(其实也相当于位移一个了)。将所有得到的数相加完毕之后,我们就能得到我们想要的结果。先附上完整代码:
#include<iostream>
#include<stdlib.h>
#include<string>
int tmp[501] = { 0 };
using namespace std;
/*
此部分用来做乘法,也就是将乘数的某一位与被乘数整体相乘;
其步骤依然是一位一位乘;
参数分别是是被乘数,乘数的某一位,进位值;
*/
void mutiply(int a[], int bi, int pre)
{
for (int i = 499; i >= 0; i--)
{
tmp[i + 1] = (a[i] * bi + pre) % 10;
pre = (a[i] * bi + pre) / 10;
}
}
/*
此部分做错位加法,上一步得到的值通过错位的方式与answer的相应位置相加;
参数分别是答案,答案下标;
其中局部变量indexTMP 代表tmp数组的下标;
pre代表进位值;
*/
void add(int answer[], int indexAnswer)
{
int indexTMP = 500;
int pre = 0;
while (indexTMP >= 0)
{
int value = answer[indexAnswer] + tmp[indexTMP] + pre;
answer[indexAnswer] = (answer[indexAnswer] + tmp[indexTMP] + pre) % 10;
pre = value / 10;
indexAnswer--;
indexTMP--;
}
}
/*
此部分调用以上两部分功能,通过循环来实现整体的乘法
参数分别是:被乘数,乘数,答案
*/
void function(int a[], int b[], int answer[])
{
for (int i = 499; i >= 0; i--)
{
mutiply(a, b[i], 0);
add(answer, i + 500);
}
}
int main()
{
string a;
string b;
string c;
cin >> a;
cin >> b;
int a1[500] = { 0 };
int b1[500] = { 0 };
int answer[1000] = { 0 };
int maxlength = a.length();
int minlength = b.length();
if (maxlength < minlength)
{
int tmp = minlength;
minlength = maxlength;
maxlength = tmp;
}
/*
此部分是将字符串的数值转化到int型数组中
*/
for (int i = a.length() - 1, j = 499; i >= 0; i--, j--)
{
a1[j] = a[i] - 48;
}
for (int i = b.length() - 1, j = 499; i >= 0; i--, j--)
{
b1[j] = b[i] - 48;
}
function(a1, b1, answer);
/*
不输出前面多余的0,从真正有意义的数值开始输出,index用来记录该下标
*/
int index = 0;
for (int i = 0; i <= 999; i++)
{
if (answer[i] != 0)
{
index=i;
break;
}
}
if(index!=0)
{
for (int k=index; k < 1000; k++)
{
cout << answer[k];
}
}
else
{
cout << "0";
}
system("pause");
return 0;
}
注意,本程序涉及全局变量tmp[501],改变量用来保存乘数的某一位乘以被乘数所得到的值,其最大为501位;此外,在function里,add方法的调用,第二个参数是i+500;这里保证了每一次相加时的错位,也就是相当于相加时tmp相对于answer整体左移一位,符合笔算的规则。
编译执行结果:
500位以内正整数随便乘,当然也可以改成正负数都可以,这里就不演示了,如有疑问欢迎评论区留言,欢迎大家转载!