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