长整数四则运算_双向循环链表

[ 问题描述 ]
设计程序实现两个任意长整数的求和运算。
[ 基本要求 ]
利用双向循环链表实现长整数的存储, 每个结点含一个整型变量. 任何整型变量的范围是 -(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;
}


猜你喜欢

转载自blog.csdn.net/qq_32767041/article/details/69525413
今日推荐