C++字符串乘法

这个问题的官方学名似乎叫,大数乘法。

名字相当霸气,不过现在都有很成熟的解决方案了,运用乘法基本原理也能自己搞一个出来。

写文章便于以后来回忆。

 

一、横向比较

对比了几个实现方法。(数据范围[1,10^8],重复10^5次)

1.最好理解的版本是用std::vector存临时结果,然后遍历vector逐位递进。优点是可读性很强,基本符合自然语言描述的过程。缺点是这个算法很慢,貌似用到STL容器的算法都会慢一点。 --- 17.111秒

//参考https://blog.csdn.net/S1766434333/article/details/77839226

 

2.不使用STL容器,直接用string本身可以随机访问的特性来存储临时结果,最后遍历取出。

优点是用的都是string类的库函数,速度快了许多。缺点是代码形式复杂。

---8.519秒

//参考https://blog.csdn.net/shanghairuoxiao/article/details/76577357

 

3.使用一个int[]数组来存结果,用malloc和memset实现内存级别的控制。

开销小,速度快,可读性也强。

强烈推荐!

---1.598秒

//参考https://blog.csdn.net/a781558066/article/details/45192005

 

重点研究第三种。

 

二、几个重点

①m位数乘以n位数的结果,最长为m+n位。(自行证明)

②在计算机中,以string标示的数字,下标i乘以下标j的结果,理应放在下标(i+j)处。

但是,考虑到进位,需要留一位固定的answer[0]给最高位进位的数字。

于是(i,j)乘积的临时结果temp的实际下标应该为answer[i+j+1]。

 

 

以上图右侧为例,i=0,j=0时,a[i]=4,b[j]=4,temp=4*4=16。

temp=a[i]*b[j]; //temp=16

将temp存放于answer[i+j+1]位置,即

answer[i+j+1]+=temp; //answer[1]+=16

然后进位处理

answer[0]+=answer[1]/10;
answer[1]+=answer[1]%10;

不断重复上述过程即可。

 

注意,要从个位开始乘法累加,在string中是从str[str.size()-1]开始到str[0]结束。

 

在①中可以证明,m位乘n位结果最多m+n位,因此我们申请m+n位的数组,下标最大值为m+n-1。

在②中显然,下标i<=m-1,下标j<=n-1,则下标i+j+1<=m+n-1,恰好为数组下标的最大值。

从两个方向获得的上界吻合,所申请空间的利用率为100%。

 

 

三、具体实现

 

代码如下:

//#include <string>
//#include <cstring>

//亲测参数用char*速度会比string&快上很多很多!!!
//调用时stringMultiply(stra.c_str(),strb.c_str());

string stringMultiply(const char *str1, const char *str2)
{
	int len1 = strlen(str1); //必须用int不能用unsigned
	int len2 = strlen(str2);
	int i, j;

	//结果最多m+n位,申请m+n位空间
	char *res = (char *)malloc(sizeof(char)*(len1 + len2)); 
	memset(res, 0, sizeof(char)*(len1 + len2));
	for (i = len1 - 1; i >= 0; --i)
		for (j = len2 - 1; j >= 0; --j)
		{
			res[i + j + 1] += (str1[i] - '0')*(str2[j] - '0'); //数乘后累加
			res[i + j] += res[i + j + 1] / 10;//进位
			res[i + j + 1] %= 10;//进位结束
		}
	int count = 0;
	//由于m+n位是理论上限值,若实际没有占满,则左侧会有多余的0需要剔除
	while (res[count] == 0)  
	{
		count++;
	}
	//len1+len2+1是结果空间,多留一位给末位'\0',就变成了len1+len2+2
	char* ret = (char *)malloc(sizeof(char)*(len1 + len2 + 2));
	memset(ret, 0, sizeof(char)*(len1 + len2 + 2)); //末位'\0'在这一步就赋值好了
	for (j = 0, i = count; i < len1 + len2; ++j, ++i)  //非0部分赋给ret
	{
		ret[j] = res[i] + '0';
	}
	string str(ret);//这样用ret获得str,比在循环里写str+=res[i] + '0';要快一些
	//释放申请的空间
	free(res);
	free(ret);
	return  str;
}

 

其他四则运算迟点补

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值