【算法】大整数加法

1.算法描述


为了表示大整数,一般采用字符数组,这样可以表示更多位的整数。在实现大整数加法时,可模拟小学生列竖式。首先,位对齐,两个大整数的个位对个位、十位对十位、百位对百位……然后,按位相加,如果满十,则置进位为1。两个大数的高位相加时,要加上进位。


长度为n的字符数组在表示大整数时,[0]表示大整数的最高位,[n-1]表示大整数的最低位(即个位)。所以,在位对齐时,处理比较麻烦。


2.问题


2.1 九度OJ 1198


题目要求:实现一个加法器,使其能够输出a+b的值。


源代码:

1198 Accepted 908KB 2595B 120MS C / 代码

#include <stdio.h>
#include <string.h>

int main()
{
	char a[1000],b[1000],c[1000],carry[1001];     //carry[i]表示进位
	int i,j,k,temp,a_length,b_length;
	
	while(~scanf("%s%s",&a,&b))
	{
		a_length=strlen(a);
		b_length=strlen(b);
		
		if(a_length<b_length)                        //a的位数比b的位数少
		{
			memset(carry,'0',b_length+1);
			for(i=a_length-1,j=b_length-1,k=0;i>=0;i--,j--,k++)
			{
				temp=a[i]+b[j]+carry[k]-96;
				if(temp>57)
				{
					temp=temp-10;
					carry[k+1]='1';
				}
				else carry[k+1]='0';
				c[k]=(char) temp;
			}
			for(j=b_length-a_length-1,k=a_length;j>=0;j--,k++)
			{
				temp=b[j]+carry[k]-48;
				if(temp>57)
				{
					temp=temp-10;
					carry[k+1]='1';
				}
				else carry[k+1]='0';
				c[k]=(char) temp;
			}
			if(carry[b_length]=='1')               //判断最高位是否有进位
			{
				c[b_length]='1';
				c[b_length+1]='\0';
			}
			else c[b_length]='\0';
			
		}
		
		else if(a_length==b_length)
		{
			memset(carry,'0',a_length+1);
			for(i=a_length-1,k=0;i>=-0;i--,k++)
			{
				temp=a[i]+b[i]+carry[k]-96;
				if(temp>57)
				{
					temp=temp-10;
					carry[k+1]='1';
				}
				else carry[k+1]='0';
				c[k]=(char) temp;
			}
			if(carry[a_length]=='1')
			{
				c[a_length]='1';
				c[a_length+1]='\0';
			}
			else c[a_length]='\0';
		}
		
		else
		{
			memset(carry,'0',b_length+1);
			for(i=a_length-1,j=b_length-1,k=0;j>=0;i--,j--,k++)
			{
				temp=a[i]+b[j]+carry[k]-96;
				if(temp>57)
				{
					temp=temp-10;
					carry[k+1]='1';
				}
				else carry[k+1]='0';
				c[k]=(char) temp;
			}
			for(i=a_length-b_length-1,k=b_length;i>=0;i--,k++)
			{
				temp=a[i]+carry[k]-48;
				if(temp>57)
				{
					temp=temp-10;
					carry[k+1]='1';
				}
				else carry[k+1]='0';
				c[k]=(char) temp;
			}
			if(carry[a_length]=='1')
			{
				c[a_length]='1';
				c[a_length+1]='\0';
			}
			else c[a_length]='\0';
			
		}
		
		int c_length=strlen(c);
		for(i=c_length-1;i>=0;i--)
			printf("%c",c[i]);
		printf("\n");
	}	
	return 0;
 }

2.2 POJ 1503


求:输入n个大数之和。

用int数组sum存放运算结果,通过sum[ i ]>10判断是否有进位。

WA了几次,看Discuss,原来数组要开到105。

源代码:

1503 Accepted 116K 0MS C 780B 2013-08-26 10:45:55
#include "stdio.h"
#include "string.h"

#define MAX 105

int main()
{
	int sum[MAX];
	int i, j, leading_zero, ch_length;
	char ch[MAX];
	
	memset(sum,0,sizeof(sum));
	
	while(scanf("%s",&ch))
	{
		ch_length=strlen(ch);
		if(ch_length==1&&ch[0]=='0')              //judge the end of input
			break;
        for(i=MAX-1,j=ch_length-1; j>=0; i--,j--)
			sum[i]+=ch[j]-'0';
		
        for(i=MAX-1,j=ch_length-1; j>=0; i--,j--)   //deal with the carry
		{
			if(sum[i]>=10)
			{
				sum[i]%=10;
				sum[i-1]++;
			}
		}
	}
	
	/*deal with leading zero, output the sum*/
	for(i=0,leading_zero=0; i<MAX; i++)
		if(sum[i]!=0)
		{
			leading_zero=i;
			break;
		}
	for(i=leading_zero;i<MAX;i++)
		printf("%d",sum[i]);
	printf("\n");
	
	return 0;
}

2.3 POJ 2413


求:区间[a, b]上的fibonacci数有几个。

思路:用大整数加法求出前490个fibonacci数(其实,第480个fibonacci数就有100位了);用二分查找,找出a,b在fibonacci数组的位置,即可求出fibonacci数的个数。

用指针变量做形参才能改变变量的值,比如BinarySerach(, , ,*flag)而不是BinarySerach(, , ,flag)。二分查找没写好,WA了几次。代码参考十三年草 ,做了一些优化。

源代码:

2413 Accepted 168K 0MS C 2337B 2013-08-27 20:31:16
#include "stdio.h"
#include "string.h"

#define MAX 105
#define MAXnum 490

/*store fibonacci numbers*/
char fibonacci[MAXnum][MAX];

/*big inter addition*/
void Add(char *a, char *b, char *sum)
{
    int i,j,k,leading_zero;
	int temp[MAX];
	memset(temp,0,sizeof(temp));

	for(i=strlen(a)-1,j=MAX-1;i>=0;i--,j--)
		temp[j]=a[i]-'0';
	for(i=strlen(b)-1,k=MAX-1;i>=0;i--,k--)
		temp[k]+=b[i]-'0';
	
	/*标记前导0的结束位置*/
	leading_zero=j<k?j:k;

	/*deal with carry*/
    for(i=MAX-1;i>=leading_zero;i--)
	{
		if(temp[i]>=10)
		{
			temp[i]%=10;
			temp[i-1]++;
		}
	}

	/*deal with leading zero*/
	if(temp[leading_zero]==0)
		leading_zero++;
	
	for(i=0,j=leading_zero;j<=MAX-1;i++,j++)
		sum[i]=temp[j]+'0';
}

/*compute fibonacci numbers*/
void ComputeFibo()
{
    int i;
	memset(fibonacci,'\0',sizeof(fibonacci));
    strcpy(fibonacci[1],"1");
	strcpy(fibonacci[2],"2");

    for(i=3;i<MAXnum;i++)
        Add(fibonacci[i-1],fibonacci[i-2],fibonacci[i]);
}

/*compare two strings*/
int Compare(char *a, char *b)
{
    int a_length, b_length;
    a_length=strlen(a);
    b_length=strlen(b);
    if(a_length==b_length)
        return strcmp(a,b);
    else
        return a_length>b_length?1:-1;
}

/*当a不是fibonacci数时,二分查找返回的是第一个比a大的fibonacci数
  flag标记查找元素a是否属于fibonacci数组*/
int BinarySearch(int low, int high, char *a, int *flag)
{
    int pivot, comp;
    while(low<=high)
    {
        pivot=(low+high)/2;
        comp=Compare(a,fibonacci[pivot]);
        if(comp==0)
        {
            *flag=1;
            return pivot;
        }
        else if(comp<0)
            high=pivot-1;
        else
            low=pivot+1;
    }
    return low;
}

int main()
{
    char a[MAX], b[MAX];
    int a_length, b_length, a_start, b_start;
    int left_flag, right_flag;
	
    ComputeFibo();
    while(scanf("%s%s",&a,&b))
    {
        left_flag=0; right_flag=0;
		a_length=strlen(a); b_length=strlen(b);

        if(strcmp(a,"0")==0&&strcmp(b,"0")==0)
            break;

        a_start=BinarySearch(1,MAXnum-1,a,&left_flag);
        b_start=BinarySearch(a_start,MAXnum-1,b,&right_flag);

        if(right_flag)
            printf("%d\n",b_start-a_start+1);
        else
            printf("%d\n",b_start-a_start);
    }
    return 0;
}


你可能感兴趣的:(【算法】大整数加法)