大数相加(C语言)


【引入】

在现实中,当对两个超级大的整数进行加法运算的时候,这两个超级大的数以及它们的结果都是没办法用变量存起来的。但是我们可以用数组或者字符串去存储,然后在这基础上进行运算。

数组 + 整数

【题目描述】

对于非负整数 X 而言,X 的数组形式是每位数字按从左到右的顺序形成的数组。例如,如果 X = 1231,那么其数组形式为 [1,2,3,1]。
给定非负整数 X 的数组形式 A,返回整数 X+K 的数组形式。

题目来源(力扣):数组形式的整数加法

解法一

基本思路: 就是加法的竖式计算,逐位相加,满十进一。这个解法把进位单独用变量存起来。
注:a + b = c(假设 a 是M位数,b 是N位数,且M > N),c 是 M 位数或 M + 1位数,也就是说 c 最多是 M + 1 位数。
比如 999 + 999 = 1998 , 1998是四位数。

void reverseArray(int* num, int numSize)
{
    int left = 0, right = numSize - 1;
	while (left < right)
	{
		int tmp = num[left];
		num[left] = num[right];
		num[right] = tmp;
		left++;
		right--;
	}
}

int* addToArrayForm(int* num, int numSize, int k, int* returnSize) {
	int kSize = 0;
	int kNum = k;
	while (kNum)    
	{
		kSize++;
		kNum /= 10;
	}                 //上面的代码是为了计算出 k 是几位数

	int maxlen = numSize > kSize ? numSize : kSize;
	int* retArr = (int*)malloc(sizeof(int)*(maxlen + 1)); 
	int reti = 0;

	int numi = numSize - 1;
	int nextNum = 0; //进位
	while (maxlen--)
	{
		/*int sum = (num[numi] + k % 10 + nextNum) % 10;
		nextNum = (num[numi] + k % 10 + nextNum) / 10;
		numi--;*/
		
		**********************
		int a = 0;
		if (numi >= 0)
		{
			a = num[numi];   //下面有说明
			numi--;
		}
		
		int sum = (a + k % 10 + nextNum) % 10;
		nextNum = (a + k % 10 + nextNum) / 10;
		**********************
		k /= 10;
		
		retArr[reti++] = sum;
	}

	if (nextNum == 1)  //上面的循环走完了,还存在着进位。比如:99 + 62 = 161
	{
		retArr[reti++] = 1;
	}

	reverseArray(retArr, reti);
	*returnSize = reti;
	return retArr;
}

说明:while (k–) 是循环 k 次 。
而 while (–k) 是循环 k - 1 次。
在这里我们希望它循环 k 次,因而使用 while (k–) 来控制。

说明:不能写成/**/之间的,要写成 “ ******* ”之间的。原因:当 k 的位数比 num[] 的位数更大时,会出现数组越界访问。
由于我们把每位相加的结果倒着放进了数组,因此需要把数组逆置一下。
我们在刷题的时候不能只盯着给出来的示例,它给的示例一般都是比较常规的,更多的时候还是要去考虑没那么常规的情况。

注:在这里,我们当中可能有的人不明白为什么要给参数 int* returnSize,不知道是干嘛用的。
其实,当函数返回一个 int* 指针时,如果代表一个数组的话,函数一般都会有参数 int* returnSize。
在调用这个函数时,会给变量(在这里我假设变量名是 size )的地址作为参数传进去,函数执行完之后,size 的值应该是函数返回的数组的大小。
你想吗,如果没有 int* returnSize 这个参数,那么函数返回的数组的大小你是不知道的,于是访问这个数组的元素时很有可能越界。(说准确一点,连数组的界在哪都不知道)

解法二

这个解法把进位加到了整数 k 上。

int* addToArrayForm(int* num, int numSize, int k, int* returnSize) {
	int kSize = 0;
	int kNum = k;
	while (kNum)    //计算k是几位数
	{
		kSize++;
		kNum /= 10;
	}

	int maxlen = numSize > kSize ? numSize : kSize;
	int* retArr = (int*)malloc(sizeof(int)*(maxlen + 1));
	int reti = 0;

	for(int i = numSize - 1; i >=0; i--)
	{
		int sum = num[i] + k % 10;
		k /= 10;
		if(sum > 9)
		{
			k++;
			sum -= 10;
		}
		
		retArr[reti++] = sum;
	}
	
	while(k) //下面有说明
	{
		retArr[reti++] = k % 10;
		k /= 10;
	}
	
	reverseArray(retArr, reti);
	*returnSize = reti;
	return retArr;
}

说明:为了应对 k 的位数比 num[] 的位数大的情况,写了最后的while循环。把多出来的 k 的前面的那几位数直接拷到数组。

数组 + 数组

整体思路还是跟上面的 解法一 是一样的,只是都以数组的形式相加。

void reverseArray(int* num, int numSize)
{
    int left = 0, right = numSize - 1;
	while (left < right)
	{
		int tmp = num[left];
		num[left] = num[right];
		num[right] = tmp;
		left++;
		right--;
	}
}

int* addArrays(int* num1, int num1Size, int* num2, int num2Size, int* returnSize)
{
	int maxlen = num1Size > num2Size ? num1Size : num2Size;
	int* retArr = (int*)malloc(sizeof(int)*(maxlen + 1));
	int reti = 0;

	int num1i = num1Size - 1, num2i = num2Size - 1;
	int nextNum = 0; //进位
	while (maxlen--)
	{
		int a = 0;
		if (num1i >= 0)
		{
			a = num1[num1i];
			num1i--;
		}

		int b = 0;
		if (num2i >= 0)
		{
			b = num2[num2i];
			num2i--;
		}
		
		int sum = (a + b + nextNum) % 10;
		nextNum = (a + b + nextNum) / 10;
		
		retArr[reti++] = sum;
	}

	if (nextNum == 1)
	{
		retArr[reti++] = 1;
	}

	reverseArray(retArr, reti);
	*returnSize = reti;
	return retArr;
}

字符串 + 字符串

这里要先知道这么一个点,就是字符型数字怎么转换为整型数字
‘9’ - ‘0’ == 9
只需把字符型数字减去字符0即可,它们的ASCII码的差值就是我们想要的结果。

【题目描述】

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。

你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

题目来源(力扣):字符串相加

void reverseString(char* str, int len)
{
	int left = 0, right = len - 1;
	while (left < right)
	{
		char tmp = str[left];
		str[left] = str[right];
		str[right] = tmp;
		left++;
		right--;
	}
}

char * addStrings(char * num1, char * num2) {
	int maxlen = strlen(num1) > strlen(num2) ? strlen(num1) : strlen(num2);
	char* retStr = (char*)malloc(sizeof(char)*(maxlen + 2)); 
	//因为这是一个字符串,后面还要放'\0',所以不是 maxlen + 1,而是 maxlen + 2
	int reti = 0;

	int num1i = strlen(num1) - 1;
	int num2i = strlen(num2) - 1;
	int nextNum = 0;
	while (maxlen--)
	{
		char m = '0';
		if (num1i >= 0)
		{
			m = num1[num1i];
			num1i--;
		}

		char n = '0';
		if (num2i >= 0)
		{
			n = num2[num2i];
			num2i--;
		}

		int sum = ((m - '0') + (n - '0') + nextNum) % 10;
		nextNum = ((m - '0') + (n - '0') + nextNum) / 10;

		retStr[reti++] = '0' + sum;

	}

	if (nextNum == 1)
	{
		retStr[reti++] = '1';
	}

	retStr[reti] = '\0';

	reverseString(retStr, strlen(retStr));
	return retStr;
}

因为我们要进行 % 和 / 的运算,用字符型数字是不能达到要求的,因为字符型数字的运算实质上是ASCII码的运算,并且字符型数字的ASCII码与字符型数字不是绝对对应起来的(比如 ‘0’ 的ASCII码是 48 ,而不是 0 )。

更多文章
合并两个有序数组(C语言)
阶乘后的零(C语言)
调整数组顺序使奇数位于偶数前面(C语言)

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值