大整数的加法、减法、乘法,附完整代码

 本人萌新一个,要是有大佬发现bug还请一定要告诉我

 

 

一:大整数存储原理

用链栈的方式,每输入一个数字就压栈,同时用一个常量step记录数字长度放在栈顶方便后续使用,以“#”结束,分别将两个操作数压入S1和S2,结果放入S栈,完美实现任意长度的数字存储
(毕竟输入时是从左到右输入,计算时是从右到左计算,输出时又是从左往右,与栈的特点相符,经过尝试,加减运算全程确实完全符合这一规律)
二:加法
从数字个位开始即从栈顶开始,每次从S1和S2各弹出一个数,用k记录是否进位(0、1),进行一位数加法运算(S1+S2+k),将(S1+S2+k)%10压入S栈,循环执行下去,若其中一个栈已空,即直接把另一个栈加上进位k压入结果S栈,直到两个栈都为空。

三:减法
方法和加法类似,进位k在0和-1间选择
只是开始时先比较两个操作数的位数,若S1<S2则交换S1和S2位置,在输出答案前加上“-”;
bug:当两个数位数相同但实际数值S1<S2时,目前会输出“error”,得不出负数结果
还请大佬指点

四:乘法

乘法的计算思路和我们正常做竖式一样
操作数存储和上述一样(我觉得可以考虑改其它数据结构可能会更简便)
计算前根据栈顶存储的操作数长度,将更长的那个放在乘数位置(竖式的上面),另一个放下面,可以减少循环次数。因为乘数会被反复使用,所以直接申请一个数组a单独存放。
每次循环,被乘数栈弹出一个数,同时用time记录是第几次循环(关系到结果后面的补0个数),与a数组从右开始进行一位数的乘法运算,k记录进位,(S2*a[i]+k)%10压入辅助栈t,(S2*a[i]+k)/10给k。每得出一个结果便加到上一个结果上(调用上面加法的方法,本人单独写了一个jiafa_2函数(实现s+t),因为发现操作数是倒过来的,在最前面加了对栈的倒转(swap函数)对于这部分可以考虑把链栈结构改为链队列),最后得到的栈s即为乘法的结果。

大整数的加法、减法、乘法,附完整代码

 

完整可运行代码如下:

 

#include<stdio.h>
#include<stdlib.h>
typedef struct Snode{
	int data;                           //存放一位数字 
	struct Snode *next;
}Snode,*LinkStack;
void Push(LinkStack &S,int e)           //压栈 
{
	LinkStack p;
	p=new Snode;
	p->data=e;
	p->next=S;
	S=p;
}
int Pop(LinkStack &S)                   //出栈 
{
	int e;
	LinkStack p;
	if(S==NULL)return -1;
	e=S->data;
	p=S;
	S=S->next;
	delete p;
	return e;
}
void Putin(LinkStack &S1)                //录入大整数,以#结束 
{
	char A;
	int step=0;                          //step记录大整数位数 
	printf("put in num\n");
	while(1)
	{
		step++;
		scanf("%c",&A);
		if(A=='#')
			break;
		Push(S1,A-48);
	}
	Push(S1,step-1);                      //将step压在栈顶 
}
void jiafa()                              //大整数加法运算 
{
	LinkStack S1;
	S1=NULL;
	Putin(S1);                            //录入大整数S1 
	
	getchar();
	
	LinkStack S2;
	S2=NULL;
	Putin(S2);                            //录入大整数S2 
	
	LinkStack S;
	S=NULL;                               //栈S记录结果 
	int len1=Pop(S1);                     //len1记录S1长度 
	int len2=Pop(S2);                     //len2记录S2长度 
	int k=0;                              //记录是否进位 
	int c;                                //c作为中间量 
	while(S1!=NULL&&S2!=NULL)             //S1、S2都不为空 
	{
		c=Pop(S1)+Pop(S2)+k;              //c为两个栈的栈顶数字之和 
		if(c>=10)
		{
			c=c-10;
			k=1;
			Push(S,c);                    //将c的个位压入栈S 
		}else 
		{
			k=0;
			Push(S,c);
		}
	}
	if(S1==NULL&&S2==NULL&&k!=0)          //当两个栈同时为空,如果k!=0则将k压栈 
	{
		Push(S,k);                         
		k=0;
	}
	while(S1!=NULL)                       //当S1不为空,将S1和k相加后压入S栈 
	{
		c=Pop(S1)+k;
		if(c>=10)
		{
			k=1;
			c=c-10;
			Push(S,c);
		}
		else
		{
			k=0;
			Push(S,c);
		}	
	}
	while(S2!=NULL)                       //当S2不为空,将S1和k相加后压入S栈 
	{
		c=Pop(S2)+k;
		if(c>=10)
		{
			k=1;
			c=c-10;
			Push(S,c);
		}
		else
		{
			k=0;
			Push(S,c);
		}	
	}
	if(k!=0)Push(S,k);                     //当所有栈都为空时,看k!=0时将k压栈 
	while(S!=NULL)                         //针对类似99999+1的情况 
		printf("%d",Pop(S));
}

void jianfa()                              //大整数减法运算 
{
	LinkStack S1;                          //和加法一样的录入过程,默认S1为被减数,S2为减数 
	S1=NULL;
	Putin(S1);
	
	getchar();
	
	LinkStack S2;
	S2=NULL;
	Putin(S2);
	
	LinkStack S;
	S=NULL;
	int len1=Pop(S1);
	int len2=Pop(S2);
	int k=0;
	if(len1<len2)                          //当S1的位数<S2的位数, 
	{                                      // 将S1和S2交换位置,在输出结果时加-号
		S=S1;
		S1=S2;
		S2=S;
		S=NULL;
	}
	while(S1!=NULL&&S2!=NULL)              //S1、S2都不空则循环计算 
	{
		int a=Pop(S1);                     //a记录S1栈顶即减数 
		int b=Pop(S2);                     //b记录S2栈顶即被减数 
		if(a+k>=b)                         //a+k>=b即够减则直接将结果压栈 
		{
			Push(S,a+k-b);
			k=0;
		}
		else                               //不够减则将k置为-1,a加上10进行运算 
		{
			Push(S,a+k+10-b);
			k=-1;			
		}
	}
	while(S1!=NULL)                        //因为前面保证了S1长度大于等于S2,所以只要考虑S1是不是空 
	{
		int a=Pop(S1);
		if(a+k>=0)
		{
			Push(S,a+k);
			k=0;
		}
		else                                //a+k<0即还要向前借位,所以当前位置为9 ,k为-1 
		{
			k=-1;
			Push(S,9);
		}
	}
	if(k==-1)                               //S1、S2都为空,k仍为-1说明S1和S2位数相同但S1<S2,输出error报错 
	{
		printf("error\n");
		return;
	}
	if(k==0){                               //k==0说明S1-S2够减 
		int a=0;
		while((a=Pop(S))==0);               //将结果栈栈顶为0的部分弹出 
		if(a==-1)a=0;                       //如果全部为0则将a置0 
		Push(S,a);                          //将弹出的不为零的项压回去 
	};
	if(len1<len2)printf("-");
	while(S!=NULL)
		printf("%d",Pop(S));
	return;
}
void Swap(LinkStack &S)                     //将栈S首位倒转 
{
	LinkStack T;
	T=NULL;
	while(S!=NULL)
	{
		Push(T,Pop(S));
	}
	S=T;
}
void jiafa_2(LinkStack &S1,LinkStack &S2)    //针对乘法部分单独写的加法函数 
{                                            //将S1和S2相加,结果存入S1 
	Swap(S1);                                //这里获得的S1,S2都是上一次加法的结果,所以顺序正好相反,将S1倒转 
	Swap(S2);                                //将S2倒转 
	LinkStack S;
	S=NULL;
	int k=0;
	int c;
	while(S1!=NULL&&S2!=NULL)                //具体加法过程和上面相同 
	{
		c=Pop(S1)+Pop(S2)+k;
		if(c>=10)
		{
			c=c-10;
			k=1;
			Push(S,c);
		}else 
		{
			k=0;
			Push(S,c);
		}
	}
	if(S1==NULL&&S2==NULL&&k!=0)
	{
		Push(S,k);
		k=0;
	}
	while(S1!=NULL)
	{
		c=Pop(S1)+k;
		if(c>=10)
		{
			k=1;
			c=c-10;
			Push(S,c);
		}
		else
		{
			k=0;
			Push(S,c);
		}	
	}
	while(S2!=NULL)
	{
		c=Pop(S2)+k;
		if(c>=10)
		{
			k=1;
			c=c-10;
			Push(S,c);
		}
		else
		{
			k=0;
			Push(S,c);
		}	
	}
	if(k!=0)Push(S,k);
	S1=NULL;
	S1=S;                                  //把结果栈赋给S1 
}
void chenfa()                              //大整数乘法运算 
{
	LinkStack S1;                          //大整数录入过程和上面相同 
	S1=NULL;
	Putin(S1);
	
	getchar();
	
	LinkStack S2;
	S2=NULL;
	Putin(S2);
		
	LinkStack S;
	S=NULL;
	int c,k=0;
	int time=-1;                           //记录被乘数计算到第几位了 
	int len1=Pop(S1);
	int len2=Pop(S2);
	if(len1<len2)                          //比较S1\S2位数,将长的设为被乘数,即放在前面 
	{
		S=S1;
		S1=S2;
		S2=S;
		S=NULL;
		c=len1;
		len1=len2;
		len2=c; 
	}
	
	int *a=new int[len1];                   //因为被乘数会被循环使用 
	for(int i=len1-1;i>=0;i--)              //所以动态开辟数组将被乘数按位存入其中 
		a[i]=Pop(S1);
	while(S2!=NULL)                         //乘数不为空即要进行一次循环 
	{
		time++;
		c=Pop(S2);	                        //c记录乘数栈顶即最低位 
		if(time==0)                         
		{
			for(int i=len1-1;i>=0;i--)      // 从被乘数最低位开始循环 
			{
				Push(S,(c*a[i]+k)%10);      //将结果的各位压栈,十位给k 
				k=(c*a[i]+k)/10;
			}
			if(k!=0)                        //被乘数已经遍历完,k!=0则把k压栈 
				Push(S,k);
		}
		else
		{
			LinkStack t;
			t=NULL;
			for(int i=0;i<time;i++)         //从乘数的第二位开始,要为结果填充0 
				Push(t,0);
			k=0;
			for(int i=len1-1;i>=0;i--)
			{
				Push(t,(c*a[i]+k)%10);
				k=(c*a[i]+k)/10;
			}
			if(k!=0)
				Push(t,k);
			jiafa_2(S,t);
		}	
	}		
	while(S!=NULL)
		printf("%d",Pop(S));
	printf("\n");
	
}
int main()
{
	
	int n;
	printf("1.加法\n2.减法\n3.乘法\n0.退出\n ");
	printf("put in n\n");
	scanf("%d",&n);
	getchar();
	while(n!=0)
	{
		system("cls");
		switch(n)
		{
			case 1:
				{
					jiafa();
					break;
				}
			case 2:
				{
					jianfa();
					break;
				}
				case 3:
					{
						chenfa();
						break;
					}
		}
		printf("\n1.加法\n2.减法\n3.乘法\n0.退出\n");
		printf("put in n\n");
		scanf("%d",&n);
		getchar();
	}
}