机试:大数加法和大数阶乘

大数加法

大数阶乘的基础是大数加法,那么我先从大数加法看起:

题目描述:

给定整数a,b,计算a+b的值,其中a,b的位数<=10000

这种题目的特点是,就算使用long long 型去存储a,b,也是存不下的。因此,我们使用char型数组来存储这两个超级大数。

但在此之前,我们需要先回忆一下我们是如何计算两个数的加法的。我们会把这两个数按位对齐排列,然后从低位往高位计算。这样做的好处是低位运算有时会向高位产生进位,如果从高位往低位运算在不明确进位的条件下会出错。因此,我们在进行大数运算时也会从低位开始计算起。

为了实现从低位向高位的运算,我们在数组中存储大数时采用从最低位(也就是个位)开始存储。如下图:

但我们使用scanf手动输入的又是正序的数,因此需要使用一个循环帮我们完成逆序操作:

//buffer数组用于暂存输入的数(正序)
char* buffer = (char*)malloc(MAXLEN * sizeof(char));
//以下两个加数存储的并不是0~9的ASCII码,而直接是0~9,方便之后的数据运算
char a[MAXLEN + 1] = { 0 };//加数1
char b[MAXLEN + 1] = { 0 };//加数2
scanf("%s", buffer);
//a,b均采用逆序存储
for (int tmp = 0, i = strlen(buffer) - 1; i >= 0; i--) {
	a[tmp++] = buffer[i] - '0';
}
free(buffer);
buffer = (char*)malloc(MAXLEN * sizeof(char));
scanf("%s", buffer);
for (int tmp = 0, i = strlen(buffer) - 1; i >= 0; i--) {
	b[tmp++] = buffer[i] - '0';
}

以上操作,我们就可以得到两个逆序的数了。接下来就是加法运算的过程。

我们从个位开始计算起,现在逆序存储的好处就显示出来了。它们是自动对齐的,也就是说他们的个位都对应数组中第0个值、十位对应数组中第1个值....

我们要额外定义一个进位up,用来记录每次从低位向高位产生的进位。

//计算加法结果,并把计算结果存储在a数组中,因为之前我们是逆序存储的,因此在计算时,相当于从个位开始相加
	for (int up = 0, i = 0,tmp; i < MAXLEN; i++) {
		tmp = a[i] + b[i] + up;
		a[i] = tmp % 10;
		up = tmp / 10;
	}

我们现在已经得到结果了,只需要输出在控制台就可以了。但是别忘了,我们的数是逆序存储的,还要把顺序倒过来才行:

//计算过后的a数组实际上就是所得的结果,但仍然是逆序存储的,为此,在输出时我们可以将它翻转过来
	int i=MAXLEN;
	while (i >= 0) {
		//首先要去除高位多余的0,这些0不需要输出
		while (a[i] == 0)i--;
		for (; i >= 0; i--) {
			printf("%d", a[i]);
		}
	}

至此,我们完成了大数加法的计算,完整的代码如下:

#include<iostream>
#include<string>
#include<stdio.h>
#include<stdlib.h>
#define MAXLEN 10000
using namespace std;
int main() {
	char* buffer = (char*)malloc(MAXLEN * sizeof(char));
	//以下两个加数存储的并不是0~9的ASCII码,而直接是0~9,方便之后的数据运算
	char a[MAXLEN + 1] = { 0 };//加数1
	char b[MAXLEN + 1] = { 0 };//加数2
	scanf("%s", buffer);
	//a,b均采用逆序存储
	for (int tmp = 0, i = strlen(buffer) - 1; i >= 0; i--) {
		a[tmp++] = buffer[i] - '0';
	}
	free(buffer);
	buffer = (char*)malloc(MAXLEN * sizeof(char));
	scanf("%s", buffer);
	for (int tmp = 0, i = strlen(buffer) - 1; i >= 0; i--) {
		b[tmp++] = buffer[i] - '0';
	}
	//计算加法结果,并把计算结果存储在a数组中,因为之前我们是逆序存储的,因此在计算时,相当于从个位开始相加
	for (int up = 0, i = 0,tmp; i < MAXLEN; i++) {
		tmp = a[i] + b[i] + up;
		a[i] = tmp % 10;
		up = tmp / 10;
	}
	//计算过后的a数组实际上就是所得的结果,但仍然是逆序存储的,为此,在输出时我们可以将它翻转过来
	int i=MAXLEN;
	while (i >= 0) {
		//首先要去除高位多余的0,这些0不需要输出
		while (a[i] == 0)i--;
		for (; i >= 0; i--) {
			printf("%d", a[i]);
		}
	}

	return 0;
}

大数阶乘

问题描述:

对于给定的整数n,计算n!,其中n<=1000

我们可以沿用刚刚加法的核心代码,也就是下面这一段:

//计算加法结果,并把计算结果存储在a数组中,因为之前我们是逆序存储的,因此在计算时,相当于从个位开始相加
	for (int up = 0, i = 0,tmp; i < MAXLEN; i++) {
		tmp = a[i] + b[i] + up;
		a[i] = tmp % 10;
		up = tmp / 10;
	}

 只需要做亿点点改动即可:

for (i = 2; i <= n; i++) {
		for (up = 0, j = 0; j <= MAXLEN; j++) {
			tmp = arr[j] * i + up;
			arr[j] = tmp % 10;
			up = tmp / 10;
		}
}

 整数n代表我们要进行的n!中的n。所以最外层的循环所代表的含义就是阶乘次数。里面的小循环则是每次阶乘中乘法的运算。tmp仍然用来存储中间结果。

完整代码如下:

#include<iostream>
#include<string>
#include<stdio.h>
#include<stdlib.h>
#define MAXLEN 10000
using namespace std;
int main() {
	int n, i, j, up, tmp;
	char arr[MAXLEN + 1] = { 1 };
	scanf("%d", &n);
	for (i = 2; i <= n; i++) {
		for (up = 0, j = 0; j <= MAXLEN; j++) {
			tmp = arr[j] * i + up;
			arr[j] = tmp % 10;
			up = tmp / 10;
		}
	}
	for (i = MAXLEN; i >= 0; i--) {
		if(arr[i]!=0)
			for (; i >= 0; i--) {
				printf("%d", arr[i]);

			}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值