[ 问题描述 ]
设计程序实现两个任意长整数的求和运算。
[ 基本要求 ]
利用双向循环链表实现长整数的存储, 每个结点含一个整型变量. 任何整型变量的范围是 -(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
#include
#include
#include
#include
#include
#include
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->datadata)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(len10){ //如果first>second
subDnode(len1,first,second,result,i); //调用时向参数first传入较大值first
flag=1; //相减结果为正
}
if(cmpInteger(first,second)<0){ //如果firstdata=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+1data=-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;
}