[ 问题描述 ]
设计程序实现两个任意长整数的求和运算。
[ 基本要求 ]
利用双向循环链表实现长整数的存储, 每个结点含一个整型变量. 任何整型变量的范围是 -(215-1)~(215-1)。输入和输出形式: 按中国对于长整数的表
示习惯, 每四位一组,组间用逗号隔开。
[ 测试数据 ]
(1) 0;0;应输出"0"。
(2) -2345,6789;-7654,3211; 应输出"-1,0000,0000"。
(3) -9999,9999; 1,0000,0000,0000; 应输出"9999,0000,0001"。
(4) 1,0001,0001; -1,0001,0001; 应输出"0"。
(5) 1,0001,0001; -1,0001,0000; 应输出"1"。
[ 实现提示 ]
(1) 每个结点可以存放的最大整数为 215-1 = 32767 才能保证两数相加不会溢出。但若这样存,即相当于按 32768 进制数存,在十进制数与32768 进制数间
的转换十分不方便,故可以在每个结点中仅存十进制数的4 位,即不超过9999的非负整数, 整个链表被视为万进制。
(2)可以利用头结点数据域的符号代表长整数的符号。 用其绝对值表示元素结点数目。相加过程中不要破坏两个操作数链表。两操作数的头指针存于指针数
组中是简化程序结构的一种方法。不能给长整数位数规定上限。
[ 选作内容 ]
修改上述程序,使它在整型量范围是-(2n-1)~(2n-1) 的计算机上都能有效地运行。其中n 是由程序读入的参量。输入数据的分组方法可另行规定。
big_num_op.h
// // Created by Admin on 2017/3/31. // #ifndef BIG_NUM_BIG_NUM_OP_H #define BIG_NUM_BIG_NUM_OP_H #endif //BIG_NUM_BIG_NUM_OP_H #include <cstdio> #include <stdlib.h> #include <cstring> #include <cmath> #include <conio.h> #include <time.h> #include <algorithm> using namespace std; //定义结点 typedef int ListData; typedef struct dnode{ ListData data; struct dnode *prior,*next; }DblNode; typedef DblNode *DblList; //algorithm void InitList(DblList &first); void DestroyList(DblList &first); void ClearList(DblList &first); int ListLength(DblList first); void TravelList(DblList first); void PrtList(DblList first); void InputInteger(DblList &first,DblList &second); void newdnodeInset(DblList &p3,DblList &newdnode,DblList &result); void judgeAdd(int temp,int &k,DblList &newdnode); void addition(DblList &first,DblList &second,DblList &result); int cmpInteger(DblList first,DblList second); void subDnode(int len,DblList &first,DblList &second,DblList &result,int &i); void judgeSub(int temp,int &k,DblList &newdnode); void subtraction(DblList &first,DblList &second,DblList &result); void judgeMultiply(int temp,int &k,DblList &newdnode); void InitSpecial(DblList &first); void mulDnode(DblList &result,DblList &assist,int t); void multiplication(DblList &first,DblList &second,DblList &result); //view void prtWelcomeUI(); void prtMainUI(); void prtInputFormatUI(int op);
view.cpp
// // Created by Admin on 2017/3/31. // #include "big_num_op.h" void prtWelcomeUI(){ system("CLS"); printf("\n"); printf("************************ Long Integer Arithmetic Unit ************************\n"); printf("******************************************************************************\n"); printf("*************************** Input any key to enter ***************************\n"); printf("******************************************************************************\n"); if(getch()){ prtMainUI(); return; } else { prtWelcomeUI(); return; } } void prtMainUI(){ system("CLS"); time_t timep; struct tm *p; time(&timep); p = localtime(&timep); //获取系统时间 printf("%d/%d/%d\n",p->tm_year+1900,p->tm_mon+1,p->tm_mday); printf("=====================================Menu=====================================\n"); printf(" 1.addition 2.subtraction 3.multiplication\n"); printf(" 4.division 5.power 0.exit\n"); printf("==============================================================================\n"); printf("Please select the operation[1-10]: "); return; } void prtInputFormatUI(int op){ switch (op){ case 1: printf("\n===================================Addition===================================\n"); break; case 2: printf("\n=================================Subtraction==================================\n"); break; case 3: printf("\n================================Multiplication================================\n"); break; case 4: printf("\n===================================Division===================================\n"); break; case 5: printf("\n====================================Power=====================================\n"); break; default: return ; } printf("\texample\t1,2345,6789;\t-1,0001,0001;\n"); printf("==============================================================================\n\n"); }
algorithm.cpp
// // Created by Admin on 2017/3/31. // #include "big_num_op.h" //初始化带头结点的双向循环链表 void InitList(DblList &first){ first=(DblNode *)malloc(sizeof(DblNode)); //创建头结点 if(!first){ printf("\n内存分配失败!\n"); exit(1); } first->data=0; //头结点存储该长整数的总位数,初始化为0 first->prior=first->next=first; } void DestroyList(DblList &first){ DblList q,p=first->next; while (p!=first){ q=p; p=p->next; free(q); } free(first); } //清空带头结点的双循环链表(保留头结点) void ClearList(DblList &first){ DblList q,p=first->next; while (p!=first){ q=p; p=p->next; free(q); } first->data=0; first->prior=first->next=first; } //计算带头结点的双向循环链表的长度 int ListLength(DblList first){ DblList p=first->next; int count=0; while(p!=first){ p=p->next; count++; } return count; } //遍历循环链表 void TravelList(DblList first){ printf("\n===========================Testing============================\n"); DblList p=first->next; while (p!=first){ if(p->next==first) printf("%4d",p->data); else printf("%4d,",p->data); p=p->next; } printf(";\tthe number of node: %d\n",first->data); getchar(); if(getch())return; } //按格式输出循环链表 void PrtList(DblList first){ printf("\n============================Print=============================\n"); DblList p=first->next; if(first->data<0)printf("-"); else printf("+"); while (p!=first){ if(p->next==first){ if(p->data>=1000)printf("%4d",p->data); if(p->data<1000 && p->data>=100)printf("0%d",p->data); if(p->data<100 && p->data>=10)printf("00%d",p->data); if(p->data<10)printf("000%d",p->data); } else{ if(p->data>=1000)printf("%4d,",p->data); if(p->data<1000 && p->data>=100)printf("0%d,",p->data); if(p->data<100 && p->data>=10)printf("00%d,",p->data); if(p->data<10)printf("000%d,",p->data); } p=p->next; } printf(";\tthe number of node: %d\n",first->data); if(getch())return; } //存储输入的长整数 void InputInteger(DblList &first,DblList &second){ printf("Hint:the input format is showed as above(\";\"to the end)\n"); char str[3][8]={"first","second"}; DblList assist; for (int i = 0; i < 2; ++i) { if(i==0)assist=first; else assist=second; printf("Please input the %s integer : ",str[i]); DblList newdnode,p; int temp,flag=1; char ch; scanf("%d",&temp); if(temp<0){ //读取第一个结点数据,处理正负数,存储的长整数的正负与头结点data的正负一致 assist->data--; flag=0; } else assist->data++; //创建第一个结点并插入链尾 newdnode=(DblNode *)malloc(sizeof(DblNode)); newdnode->data=abs(temp); //结点数值为正,符号位存于头结点,与头结点data域的正负一致 assist->next=newdnode; newdnode->next=assist; newdnode->prior=assist; assist->prior=newdnode; p=newdnode; //p为链尾结点 scanf("%c",&ch); //判断输入是否结束 if(ch==';')continue; while (scanf("%d",&temp)){ //读取第二个结点到最后一个结点 newdnode=(DblNode *)malloc(sizeof(DblNode)); //创建新结点并插入链尾 newdnode->data=temp; newdnode->next=assist; newdnode->prior=p; p->next=newdnode; assist->prior=newdnode; if(flag)assist->data++; //更新链的长度 else assist->data--; p=newdnode; //使p指向链尾 scanf("%c",&ch); if(ch==';')break; else if(ch==',')continue; else { printf("\nInput Error!\n"); getchar(); if(getch())exit(0); return; } } } return; } //头结点的下一个位置插入新结点 void newdnodeInset(DblList &p3,DblList &newdnode,DblList &result){ p3->prior=newdnode; result->next=newdnode; newdnode->next=p3; newdnode->prior=result; p3=newdnode; } //加法进位处理 void judgeAdd(int temp,int &k,DblList &newdnode){ if(temp/10000==0){ newdnode->data=temp; k=0; } else{ newdnode->data=temp%10000; //k=temp/10000; k=1; } } //加法 void addition(DblList &first,DblList &second,DblList &result){ int len1=abs(first->data),len2=abs(second->data); int len=max(len1,len2); int smb1=first->data/abs(first->data),smb2=second->data/abs(second->data); //取符号位(判断正负) //p1:指向first当前运算结点(初始化为链尾结点),p2:指向second当前运算结点(初始化为链尾结点) DblList newdnode,p1=first->prior,p2=second->prior,p3=result; //p3:指向result当前运算结点(初始化为链尾结点) if(smb1+smb2!=0){ //两数都为正的情况 或 两数都为负的情况(负的情况可以转换为正的情况计算) int k=0,temp,i; //k:记录进位 temp:储存计算的临时结果 for (i = 0; i < len; i++) { //从最低位开始计算(即从链尾开始向前求加) newdnode=(DblNode *)malloc(sizeof(DblNode)); if(p1!=first && p2!=second){ //如果两条链均未计算到头结点 temp=p1->data+p2->data+k; judgeAdd(temp,k,newdnode); p1=p1->prior; //使指针指向下一个要计算的结点(指向高位) p2=p2->prior; //使指针指向下一个要计算的结点(指向高位) } else if(p1!=first && p2==second){ //如果second链已算到头结点,而first未到 temp=p1->data+k; judgeAdd(temp,k,newdnode); p1=p1->prior; //使指针指向下一个要计算的结点(指向高位) } else if(p1==first && p2!=second){ //如果first链已算到头结点,而second未到 temp=p2->data+k; judgeAdd(temp,k,newdnode); p2=p2->prior; //使指针指向下一个要计算的结点(指向高位) } //头结点的下一个位置插入新结点 newdnodeInset(p3,newdnode,result); } while(k){ //处理最高位计算需要进位的情况 newdnode=(DblNode *)malloc(sizeof(DblNode)); i++; temp=k; judgeAdd(temp,k,newdnode); //判断是否需要进位 //头结点的下一个位置插入新结点 newdnodeInset(p3,newdnode,result); } //两数为正的情况 if(smb1+smb2>0)result->data=i; //储存链表长度(数位总数),结果的正负与该值一致 //两数为负的情况 if(smb1+smb2<0)result->data=-i; //储存链表长度(数位总数),结果的正负与该值一致 return; } if(smb1+smb2==0){ //一正一负的情况,交由减法函数进行处理 if(smb1>0){ //first为正 second->data=abs(second->data); subtraction(first,second,result); second->data=-second->data; //恢复second的符号位 } else{ first->data=abs(first->data); subtraction(second,first,result); first->data=-first->data; //恢复first的符号位 } return; } } //减法借位处理 void judgeSub(int temp,int &k,DblList &newdnode){ if(temp>=0){ //不需要借位 newdnode->data=temp; k=0; } else{ //需要借位 newdnode->data=temp+10000; k=1; } } //比较长度相等的两个数,哪个较大 int cmpInteger(DblList first,DblList second){ DblList p1=first->next,p2=second->next; while(p1!=first){ if(p1->data==p2->data){ p1=p1->next; p2=p2->next; continue; } else if(p1->data>p2->data)return 1; else if(p1->data<p2->data)return -1; } return 0; } //减法结点数值相减处理 void subDnode(int len,DblList &first,DblList &second,DblList &result,int &i){ //函数调用时,fisrt传入值比second传入大 DblList newdnode,p1=first->prior,p2=second->prior,p3=result; //first和second的计算均从链尾结点开始(即从最低位开始计算) int temp,k=0; //k:初始借位为0 for (i = 0; i < len; i++) { //循环次数为两个数的最大长度 newdnode=(DblNode *)malloc(sizeof(DblNode)); if(p1!=first && p2!=second){ //如果两个指针均未到头结点 temp=p1->data-p2->data-k; judgeSub(temp,k,newdnode); //判断是否需要借位,并且为新结点赋值 p1=p1->prior; //使指针指向下一个要计算的结点(指向高位) p2=p2->prior; //使指针指向下一个要计算的结点(指向高位) } else { //如果p2已到头结点,而p1未到头结点 temp=p1->data-k; judgeSub(temp,k,newdnode); p1=p1->prior; } //头结点的下一个位置插入新结点 newdnodeInset(p3,newdnode,result); //在结果链表result中插入计算得到的新结点 } } //减法 void subtraction(DblList &first,DblList &second,DblList &result){ int len1=abs(first->data),len2=abs(second->data); int smb1=first->data/abs(first->data),smb2=second->data/abs(second->data); //取符号位(判断正负) //p3:指向result当前运算结点(初始化为链尾结点) DblList newdnode,p3=result; if(smb1+smb2>0){ //两数都为正的情况 int i,flag; //flag:标记结果的正负; i:标记结果的链表长度 if(len1>len2){ //如果第一个数的长度大于第二个 flag=1; //相减结果为正 subDnode(len1,first,second,result,i); //两数相减,结果存于result中 } if(len1<len2){ //如果第二个数长度大于第一个 flag=-1; //相减结果为负 subDnode(len2,second,first,result,i); //两数相减,结果存于result中 } if(len1==len2){ //如果两个数的长度相等,则比较哪个数更大 if(cmpInteger(first,second)>0){ //如果first>second subDnode(len1,first,second,result,i); //调用时向参数first传入较大值first flag=1; //相减结果为正 } if(cmpInteger(first,second)<0){ //如果first<second subDnode(len2,second,first,result,i); //调用时向参数first传入较大值second flag=-1; //相减结果为负 } if(cmpInteger(first,second)==0){ //如果两个数相等 newdnode=(DblNode *)malloc(sizeof(DblNode)); newdnode->data=0; //相减结果为0; newdnodeInset(p3,newdnode,result); flag=1; //计算结果为正 i=1; } } //处理计算结果的正负及链表长度 if(flag==1)result->data=i; else result->data=-i; return; } if(smb1+smb2<0){ //两个都为负的情况,可转换为两个为正相减的情况 //转换为两个正数相减 first->data=abs(first->data); second->data=abs(second->data); subtraction(second,first,result); //递归调用subtraction函数处理 //恢复两个数符号位的正负情况 first->data=-first->data; second->data=-second->data; return; } if(smb1+smb2==0){ //一正一负 if(first->data>0 && second->data<0){ //first为正second为负的情况 second->data=abs(second->data); //转换为两个正数相加 addition(first,second,result); //交由加法函数进行处理 second->data=-second->data; //恢复原输入数据的符号位的正负情况 } if(first->data<0 && second->data>0){ //second为正first为负的情况 first->data=abs(first->data); //转换为两个正数相加 addition(first,second,result); //交由加法函数进行处理 first->data=-first->data; //恢复原输入数据的符号位的正负情况 result->data=-result->data; //两数相减结果为负 } return; } } //乘法进位处理 void judgeMultiply(int temp,int &k,DblList &newdnode){ if(temp/10000==0){ newdnode->data=temp; k=0; } else{ newdnode->data=temp%10000; k=temp/10000; } } //初始化链表数值为0; void InitSpecial(DblList &first){ DblList newdnode=(DblNode *)malloc(sizeof(DblNode)); newdnode->data=0; newdnode->next=newdnode->prior=first; first->next=first->prior=newdnode; first->data=1; } //乘法结点相加处理 void mulDnode(DblList &result,DblList &assist,int t){ DblList newdnode,p1=result,p2=assist->prior; int temp,k=0; while(t--) p1=p1->prior; //处理起始相加位置 while (p2!=assist){ if(p1->prior!=result){ temp=p1->prior->data+p2->data+k; judgeMultiply(temp,k,p1->prior); p1=p1->prior; } else{ newdnode=(DblNode *)malloc(sizeof(DblNode)); temp=p2->data+k; judgeMultiply(temp,k,newdnode); newdnodeInset(p1,newdnode,result); result->data++; } p2=p2->prior; } while(k) { //处理最高位计算需要进位的情况 newdnode = (DblNode *) malloc(sizeof(DblNode)); temp = k; judgeMultiply(temp, k, newdnode); //判断是否需要进位 //头结点的下一个位置插入新结点 newdnodeInset(p1, newdnode, result); result->data++; } } //乘法 void multiplication(DblList &first,DblList &second,DblList &result){ int smb1=first->data/abs(first->data),smb2=second->data/abs(second->data); //取符号位(判断正负) DblList assist; //辅助计算链表,存储临时计算结果 InitList(assist); //初始化辅助链表 InitSpecial(result); //初始化result数值为0,长度为1; DblList newdnode,p1,p2=second->prior,p4; int temp,i=0,t; //temp:储存临时结果 t:处理起始相加位置 while(p2!=second){ t=i++; int k=0; p1=first->prior; p4=assist; while (p1!=first){ newdnode=(DblNode *)malloc(sizeof(DblNode)); temp=p2->data*p1->data+k; judgeMultiply(temp,k,newdnode); newdnodeInset(p4,newdnode,assist); assist->data++; //每添加一个新的结点,辅助链表长度+1 p1=p1->prior; } p2=p2->prior; while(k){ //处理最高位计算需要进位的情况 newdnode=(DblNode *)malloc(sizeof(DblNode)); temp=k; judgeMultiply(temp,k,newdnode); //判断是否需要进位 //头结点的下一个位置插入新结点 newdnodeInset(p4,newdnode,assist); assist->data++; } mulDnode(result,assist,t); ClearList(assist); } if(smb1+smb2==0)result->data=-result->data; else result->data=abs(result->data); return; } /* //乘法 void multiplication(DblList &first,DblList &second,DblList &result){ int len1=abs(first->data),len2=abs(second->data); int smb1=first->data/abs(first->data),smb2=second->data/abs(second->data); //取符号位(判断正负) DblList assist1,assist2; //辅助计算链表,存储临时计算结果 InitList(assist1); //初始化辅助链表1 InitList(assist2); //初始化辅助链表2 InitSpecial(assist2); //初始化辅助链表2数值为0,长度为1; DblList newdnode,p1,p2=second->prior,p4; int temp,t; //temp:储存临时结果 t:处理补0操作(需要添加多少个结点的0) for (int i = 0; i < len2; ++i) { t=i; int k=0; //k:记录进位 p4=assist1; p1=first->prior; for (int j = 0; j < len1; ++j) { newdnode=(DblNode *)malloc(sizeof(DblNode)); temp=p2->data*p1->data+k; judgeMultiply(temp,k,newdnode); newdnodeInset(p4,newdnode,assist1); assist1->data++; //每添加一个新的结点,辅助链表长度+1 p1=p1->prior; } p2=p2->prior; while(k){ //处理最高位计算需要进位的情况 newdnode=(DblNode *)malloc(sizeof(DblNode)); assist1->data++; temp=k; judgeMultiply(temp,k,newdnode); //判断是否需要进位 //头结点的下一个位置插入新结点 newdnodeInset(p4,newdnode,assist1); } while(t--){ //补0操作:在辅助链表assist链尾补0 newdnode=(DblNode *)malloc(sizeof(DblNode)); newdnode->data=0; newdnode->prior=assist1->prior; newdnode->next=assist1; assist1->prior->next=newdnode; assist1->prior=newdnode; assist1->data++; //每添加一个新的结点,辅助链表长度+1 } addition(assist2,assist1,result); if(i+1<len2){ //交换assist2和result两个链表 DblList exchange=assist2; assist2=result; result=exchange; ClearList(result); ClearList(assist1); } else{ DestroyList(assist1); DestroyList(assist2); } } if(smb1+smb2==0)result->data=-result->data; else result->data=abs(result->data); return; } */ /* //转换为字符串 void toString(DblList first,int &a[]){ DblList p1=first->next; int i=0; while (p1!=first){ a[i++]=p1->data; } } //除法 void division(DblList &first,DblList &second,DblList result){ int len1=abs(first->data),len2=abs(second->data); int smb1=first->data/abs(first->data),smb2=second->data/abs(second->data); //取符号位(判断正负) int a[10000],b[10000]; } */
main.cpp
#include "big_num_op.h" int main(){ prtWelcomeUI(); DblList first,second,result; int op; InitList(first); InitList(second); InitList(result); for (;;) { scanf("%d",&op); if(op==0)break; if(op<0||op>5){ system("cls"); prtMainUI(); continue; } switch (op){ case 1: prtInputFormatUI(op); InputInteger(first,second); //TravelList(first); //testing 测试输入数据 //TravelList(second); PrtList(first); PrtList(second); addition(first,second,result); PrtList(result); break; case 2: prtInputFormatUI(op); InputInteger(first,second); PrtList(first); PrtList(second); subtraction(first,second,result); PrtList(result); break; case 3: prtInputFormatUI(op); InputInteger(first,second); PrtList(first); PrtList(second); multiplication(first,second,result); PrtList(result); break; case 4: prtInputFormatUI(op); InputInteger(first,second); break; case 5: prtInputFormatUI(op); InputInteger(first,second); break; default: return 0; } ClearList(first); ClearList(second); prtMainUI(); } return 0; }