1. 程式人生 > >長整數四則運算_雙向迴圈連結串列

長整數四則運算_雙向迴圈連結串列

[ 問題描述 ]
設計程式實現兩個任意長整數的求和運算。
[ 基本要求 ]
利用雙向迴圈連結串列實現長整數的儲存, 每個結點含一個整型變數. 任何整型變數的範圍是 -(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;
}