大整数相乘 C++

题目描述

有两个用字符串表示的非常大的大整数,算出他们的乘积,也是用字符串表示。不能用系统自带的大整数类型。

输入描述

空格分隔的两个字符串,代表输入的两个大整数

输出描述

输入的乘积,用字符串表示

示例

输入:

72106547548473106236 982161082972751393

输出:

70820244829634538040848656466105986748

解题思路

假设,两个字符串分别为str1,str2。长度分别为len1,len2。则相乘所得的数最长为len1+len2位。
str2的最后一位(即str2[len2-1])与依次与str1的每一位数相乘。
str2[len2-1]str1[len1-1]相乘,即最后一位和最后一位相乘,所得的乘积加到数组的第0位。
str2[len2-1]str1[len1-2]相乘,即最后一位和倒数第二位相乘,所得的乘积在加入的时候应该往前移一位,所以应该存到数组的第1位。(因为我们的数组是倒着存结果,所以前移一位应该是加到数组的后一位中。)
因此,相乘和存数的关系是:当str2[i]str2[j]相乘时,乘积存放在数组的第[len1-1-i]+[len2-1-j]
注意:这时得到的数组是倒的。因为我们把个位数的乘积放到了数组的第一位
计算加和时,根据判断乘积与10的大小,来确定是否需要进位。若进位,则将进位与前一位相加,加法如前面。这里的加法我采用的是递归方法。

代码如下

#include<iostream>
#include<vector>
#include<string>

using std::vector;
using namespace std;

//加法算法,进位采用递归
vector<int> add(vector<int> result, int num, int res)
{
	int sum;
	sum = result[num] + res;
	if (sum >= 10)	//有进位
	{
		int odd = sum % 10;
		int ten = sum / 10;
		result[num] = odd;
		result = add(result, num + 1, ten);	//将进位加入下一位
		
	}
	else
		result[num] = sum;
	return result;
}


int main()
{
	string str1;//乘数
	string str2;//被乘数
	cin >> str1 >> str2;
	int len1 = str1.size();
	int len2 = str2.size();
	int n = len1 + len2;	//最大可能位数
	vector<int> result(n);	//	创建空字符串,size为n
	char res;
	for (int i = len1-1; i >= 0; i--)
	{
		for (int j = len2-1; j >= 0; j--)
		{
			int num = (len1 - 1 - i) + (len2 - 1 - j);  //下标
			int num1 = str1[i] - '0';	//字符串中数组转化为整数
			int num2 = str2[j] - '0';
			int pro = num1 * num2;		//乘积
			result = add(result, num, pro);		//结果加到数组相应的位置中
		}
	}
	//将数组取出来到字符串里,此时数组是倒序的。
	if (result[n - 1] == 0)		//我们首先要判断,是不是n位(可能是n-1位)。数组的最后一位是乘积的最高位,看是否为0;
	{
		n--;		//为0,则后续读数不能把最后一位读入。此处将n减1
	}
	
	for(int i=0;i<n;i++)		//此时n的值可以确定为结果的位数,将数组中的数转化为字符串
	{
		res= result[n - i - 1] + '0';
		cout << res;
	}
	return 0;
}

优秀算法

这是牛客网排名第一的算法。加法有所不同。他是将进位记下,然后将进位加到下一次的乘积上。但是在每次与被乘数所有的位数乘完一次后,要看看最后一次的乘法有没有进位,然后加到该加的地方,再将进位清零。因为如果再带入循环,移位会变为0,那进位所加的地方就错误了。

#include<iostream>
#include<string>
using namespace std;
//移位进位法
string Mul(string left, string right)
{
 	size_t Lsize = left.size();		//size_t = unsigned int
    size_t Rsize = right.size();
    size_t Size = Lsize + Rsize;	//最长位数
    string res(Size, '0');
 
    int takevoer = 0;//进位
    int offset = 0;//移位
 
    size_t idx = 1, j = 1;
    for (idx = 1; idx <= Rsize; ++idx)
    {
        takevoer = 0;
        int rightnum = right[Rsize - idx] - '0';
        //计算每一位与left相乘
        for (j = 1; j <= Lsize; ++j)
        {
            char resBit = res[Size - j - offset] - '0';		//取res存储对应位的数字
            int num = rightnum * (left[Lsize - j] - '0') + takevoer + resBit;//将两个数相乘,将进位和数组内存的数加入
            takevoer = num / 10;
            res[Size - j - offset] = num % 10 + '0';		//先把个位存进去
        }
        if (takevoer != 0)
            res[Size - j - offset] = takevoer + '0';
        offset++;
    }
 
    //如果没有进位的话,res最高位没有数字
    if (res[0] == '0')
        res.erase(0, 1);
    return res;
}
 
int main()
{
    string s1, s2;
    cin >>s1 >> s2;
    string str=Mul(s1,s2);
    cout << str << endl;
}

分治法实现大整数乘法

https://blog.csdn.net/qq_36268036/article/details/80013749

猜你喜欢

转载自blog.csdn.net/li_lala/article/details/89218554