双向循环链表实现大数四则运算
来源:互联网 发布:靠网络赚钱 编辑:程序博客网 时间:2024/06/08 07:10
本学期数据结构课程设计的第一个作业。
初步想法:
使用
设
则乘法复杂度:
(压位处理,其中链表每一个节点存储四位数据)
除法则枚举答案的每一位,按位更新,复杂度
代码:(详细注释)
#include<cstdio>#include<cmath>#include<string>#include<iostream>#include<algorithm>using namespace std;typedef int ElemType;#define OK 1;#define Error 0;#define Wrong -1;#define Over_Flow 0;//双向循环链表实现部分class LinkNode{ //链表结点public: ElemType data; LinkNode *next,*prev;};class LinkList{ //带头节点的双向循环链表public: LinkNode *head; int len;};void InitList(LinkList &L){ //初始化链表 L.len = 0; L.head = new LinkNode; L.head->next = L.head->prev = L.head;}void ClearList(LinkList &L){ //清空链表 LinkNode *p = L.head->next,*q; while(p != L.head){ q = p->next; delete p; p = q; } L.head->next = L.head->prev = L.head; L.len = 0;}void DestroyList(LinkList &L){ //销毁链表 ClearList(L); delete L.head; L.head = NULL;}bool ListEmpty(LinkList &L){ //判断链表是否为空 if(L.len) return false; else return true;}ElemType ListLength(LinkList& L){ //求链表长度 return L.len;}bool InsertList(LinkList& L,ElemType data,int pos){ //在链表的第pos个位置之后插入数据data if(pos<0 || pos>L.len) return Error; // 0 <= pos <= L.len LinkNode *p = L.head; if(pos <= L.len-pos+1){ //通过后继寻找位置 for(int i=1 ;i<=pos ;i++){ if(p == NULL) return Error; p = p->next; } } else{ //通过前驱寻找位置 for(int i=1 ;i<=L.len-pos+1 ;i++){ if(p == NULL) return Error; p = p->prev; } } LinkNode *q = new LinkNode; q->data = data; q->next = p->next; q->prev = p; p->next->prev = q; p->next = q; L.len++; return OK;}bool QueryList(LinkList& L,int pos,ElemType& e){ //询问链表第pos个位置的值,通过e返回 if(pos<1 || pos>L.len) return Error; // 1 <= pos <= L.len LinkNode *p = L.head; if(pos <= L.len-pos+1){ //通过后继寻找位置 for(int i=1 ;i<=pos ;i++){ if(p == NULL) return Error; p = p->next; } } else{ //通过前驱寻找位置 for(int i=1 ;i<=L.len-pos+1 ;i++){ if(p == NULL) return Error; p = p->prev; } } e = p->data; return OK;}bool DeleteList(LinkList &L,int pos,ElemType& e){ //删除第pos个位置的值,通过e返回 if(pos<1 || pos>L.len) return Error; // 1 <= pos <= L.len LinkNode *p = L.head; if(pos <= L.len-pos+1){ //通过后继寻找位置 for(int i=1 ;i<=pos ;i++){ if(p == NULL) return Error; p = p->next; } } else{ //通过前驱寻找位置 for(int i=1 ;i<=L.len-pos+1 ;i++){ if(p == NULL) return Error; p = p->prev; } } e = p->data; p->prev->next = p->next; p->next->prev = p->prev; delete p; L.len--; return OK;}//四则运算部分//输入部分string s; //用于存储输入的大数const ElemType mod = 10000;//设定或者改变大数的符号void BigInteger_Change_Symbol(LinkList &L,bool Positive){ if(Positive) L.head->data = 1; else L.head->data = 0;}//输入大数bool BigInteger_Input(LinkList &L){ InitList(L); puts("Please input your Big_Integer(if negative, please add \"- \" before the number) :"); cin >> s; int len = s.length(); if(len == 0) return Error; ElemType data = 0; int i = 0; //设定大数符号 if(s[0] == '-'){ BigInteger_Change_Symbol(L,false); i++; } else BigInteger_Change_Symbol(L,true); for(;i<len ;i++){ if(s[i] == ','){ InsertList(L,data,0); data = 0; } else{ data = data*10 + (s[i]-'0'); } } InsertList(L,data,0); return OK;}//去掉大数的前导零bool BigInteger_Delete_PreZero(LinkList& L){ LinkNode* p = L.head->prev,*q; while(p!=L.head && !p->data){ L.len--; p->prev->next = p->next; p->next->prev = p->prev; q = p->prev; delete p; p = q; } return OK;}//输出Big_Integerbool BigInteger_Output(LinkList &L){ //负数特殊处理 if(L.head->data == 0) printf("-"); BigInteger_Delete_PreZero(L); LinkNode* p = L.head->prev; if(p == L.head){ printf("0"); return OK; } printf("%d",p->data); while(p->prev != L.head){ p = p->prev; printf(",%04d",p->data); } return OK;}//BigInteger 进位或者借位处理bool BigInteger_Carry(LinkList& L){ if(L.len == 0) return Error; LinkNode* p = L.head->next; while(p->next != L.head){ if(p->data >= mod){ //需要进位 p->next->data += p->data/mod; p->data %= mod; } while(p->data < 0){ //需要借位处理 p->next->data--; p->data += mod; } p = p->next; } //最高位特殊处理(减法函数保证始终是大绝对值减小绝对值) if(p->data >= mod){ //最高位进位 ElemType add = p->data/mod; p->data %= mod; InsertList(L,add,L.len); } return OK;}//求大数的位数int BigInteger_Digit(LinkList& L){ if(L.len == 0) return 0; int digit = (L.len-1)*4; ElemType data = L.head->prev->data; while(data){ digit++; data /= 10; } return digit;}/*比较a,b的绝对值的大小 a>b 返回1 a=b 返回0 a<b 返回-1*/int BigInteger_Compare(LinkList& a,LinkList &b){ if(BigInteger_Digit(a) != BigInteger_Digit(b)){ if(BigInteger_Digit(a) > BigInteger_Digit(b)) return 1; else return -1; } LinkNode* p = a.head->prev; LinkNode* q = b.head->prev; while(p != a.head && q != b.head){ if(p->data > q->data) return 1; if(p->data < q->data) return -1; p = p -> prev; q = q -> prev; } return 0;}/*四则运算部分说明:1).因函数之间存在相互调用,如 (-a)-b = -(a+b) 和 a+(-b) = a-b 故运算函数在main函数后面实现2).乘法使用FFT算法优化,设n为最大值的位数,则复杂度为: O((n/4)*log(n/4))3).除法使用牛顿迭代法优化,复杂度同(2)中乘法操作*///计算Big_Integer a+b,结果用c返回bool BigInteger_Add(LinkList a,LinkList b,LinkList& c);//计算 Big_Integer a-b,结果用c返回bool BigInteger_Minus(LinkList a,LinkList b,LinkList& c);//计算Big_Integer a*b,结果用c返回bool BigInteger_Multi(LinkList a,LinkList b,LinkList& c);//计算Big_Integer a/b,结果用c返回bool BigInteger_Division(LinkList a,LinkList b,LinkList& c);//功能测试部分LinkList a,b,c;int main(){ //输入部分 if(!BigInteger_Input(a) || !BigInteger_Input(b)){ puts("Error in Input"); return 0; } //去掉前导零 BigInteger_Delete_PreZero(a); BigInteger_Delete_PreZero(b); //加法 puts(""); if(!BigInteger_Add(a,b,c)){ puts("Error in Add"); return 0; } puts("The result of Add: "); BigInteger_Output(c); //减法 puts(""); if(!BigInteger_Minus(a,b,c)){ puts("Error in Minus"); return 0; } puts("The result of Minus: "); BigInteger_Output(c); //乘法 puts(""); if(!BigInteger_Multi(a,b,c)){ puts("Error in Multi"); return 0; } puts("The result of Multi: "); BigInteger_Output(c); //除法 puts(""); if(!BigInteger_Division(a,b,c)){ puts("Error in Division"); return 0; } puts("The result of Division: "); BigInteger_Output(c); return 0;}//计算Big_Integer a+b,结果用c返回bool BigInteger_Add(LinkList a,LinkList b,LinkList& c){ if(a.head->data && b.head->data){ //若a,b>0 则 c>0 InitList(c); BigInteger_Change_Symbol(c,true); } else if(!(a.head->data) && !(b.head->data)){ //若a,b<0 则 c<0 且 |c| = |a| + |b| InitList(c); BigInteger_Change_Symbol(c,false); } else{ if(a.head->data){ BigInteger_Change_Symbol(b,true); if(!BigInteger_Minus(a,b,c)) return Error; } else{ BigInteger_Change_Symbol(a,true); if(!BigInteger_Minus(b,a,c)) return Error; } return OK; } LinkNode *p = a.head->next; LinkNode *q = b.head->next; while(p != a.head && q != b.head){ ElemType data = p->data + q->data; InsertList(c,data,c.len); p = p->next; q = q->next; } while(p != a.head){ InsertList(c,p->data,c.len); p = p->next; } while(q != b.head){ InsertList(c,q->data,c.len); q = q->next; } BigInteger_Carry(c); return OK;}//计算 Big_Integer a-b,结果用c返回bool BigInteger_Minus(LinkList a,LinkList b,LinkList& c){ if(!a.head->data && b.head->data){ BigInteger_Change_Symbol(b,false); if(!BigInteger_Add(a,b,c)) return Error; return OK; } if(a.head->data && !b.head->data){ BigInteger_Change_Symbol(b,true); if(!BigInteger_Add(a,b,c)) return Error; return OK; } if(!a.head->data && !b.head->data){ BigInteger_Change_Symbol(a,true); BigInteger_Change_Symbol(b,true); swap(a,b); } InitList(c); int mark = BigInteger_Compare(a,b); if(mark == 1) BigInteger_Change_Symbol(c,true); else if(mark == 0){ return OK; } else{ BigInteger_Change_Symbol(c,false); swap(a,b); } LinkNode *p = a.head->next,*q = b.head->next; while(p!=a.head && q!=b.head){ ElemType data = p->data - q->data; InsertList(c,data,c.len); p = p->next; q = q->next; } while(p != a.head){ InsertList(c,p->data,c.len); p = p->next; } BigInteger_Carry(c); return OK;}//计算Big_Integer a*b,结果用c返回//使用FFT优化,设n为最大值的位数,则复杂度为: O((n/4)*log(n/4))//定义复数类class Comp{public: double r,i; Comp(double _r = 0,double _i = 0){r = _r;i = _i;} Comp operator+(const Comp x){return Comp(r+x.r,i+x.i);} Comp operator-(const Comp x){return Comp(r-x.r,i-x.i);} Comp operator*(const Comp x){return Comp(r*x.r-i*x.i,r*x.i+i*x.r);}}*x1,*x2;//定义圆周率,用于求解单位复数根const double PI = acos(-1.0);//快速傅里叶变换的实现void FFT(Comp a[],int n,int t){ for(int i=1,j=0; i<n-1 ;i++){ for(int s=n;j^=s>>=1,~j&s;); if(i<j) swap(a[i],a[j]); } for(int d=0;(1<<d)<n ;d++){ int m = 1<<d,m2 = m<<1; double o = PI/m*t;Comp _w(cos(o),sin(o)); for(int i=0 ;i<n ;i+=m2){ Comp w(1,0); for(int j=0 ;j<m ;j++){ Comp &A = a[i+j+m],&B = a[i+j],t = w*A; A = B-t;B = B+t;w = w*_w; } } } if(t==-1) for(int i=0 ;i<n ;i++) a[i].r/=n;}bool BigInteger_Multi(LinkList a,LinkList b,LinkList& c){ int n = 1; //快速傅里叶变换所需长度 while(n < a.len+b.len) n<<=1; x1 = new Comp[n+10]; x2 = new Comp[n+10]; ElemType data; for(int i=0 ;i<a.len ;i++){ QueryList(a,i+1,data); x1[i] = Comp(data,0); } for(int i=a.len ;i<n ;i++) x1[i] = Comp(0,0); for(int i=0 ;i<b.len ;i++){ QueryList(b,i+1,data); x2[i] = Comp(data,0); } for(int i=b.len ;i<n ;i++) x2[i] = Comp(0,0); FFT(x1,n,1);FFT(x2,n,1); for(int i=0 ;i<n ;i++) x1[i] = x1[i]*x2[i]; FFT(x1,n,-1); //判断结果的正负号 InitList(c); if(a.head->data == b.head->data) BigInteger_Change_Symbol(c,true); else BigInteger_Change_Symbol(c,false); //保存结果 for(int i=0 ;i<n ;i++){ data = (ElemType)(x1[i].r + 0.5); InsertList(c,data,c.len); } //进位 BigInteger_Carry(c); //去掉前导0 BigInteger_Delete_PreZero(c); return OK;}//计算Big_Integer a/b,结果用c返回bool BigInteger_Division(LinkList a,LinkList b,LinkList& c){ if(b.len == 0) return Error; if(BigInteger_Compare(a,b) == -1) return OK; //a<b 则 a/b = 0 InitList(c); //确定答案的正负号 if(a.head->data == b.head->data) BigInteger_Change_Symbol(c,true); else BigInteger_Change_Symbol(c,false); //取绝对值,方便减法运算 BigInteger_Change_Symbol(a,true); BigInteger_Change_Symbol(b,true); int add = BigInteger_Digit(a) - BigInteger_Digit(b); LinkList d;InitList(d);BigInteger_Change_Symbol(d,true); LinkList p;InitList(p);BigInteger_Change_Symbol(p,true); for(int i=add ;i>=0 ;i--){ ClearList(d);BigInteger_Change_Symbol(d,true); int now = i; while(now>=4){ InsertList(d,0,0); now -= 4; } if(now == 0) InsertList(d,1,d.len); else if(now == 1) InsertList(d,10,d.len); else if(now == 2) InsertList(d,100,d.len); else InsertList(d,1000,d.len); BigInteger_Multi(b,d,p); while(BigInteger_Compare(a,p) != -1){ BigInteger_Minus(a,p,a); BigInteger_Add(c,d,c); BigInteger_Delete_PreZero(a); } } BigInteger_Carry(c); return OK;}
阅读全文
0 0
- 双向循环链表实现大数四则运算
- 长整数四则运算_双向循环链表
- 双向循环链表实现
- 大数四则运算的实现
- 实现大数四则运算
- 数组实现大数四则运算
- 双向循环链表的实现
- 简单实现双向循环链表
- 双向循环链表的c++ 实现
- Linux双向循环链表的实现
- 双向循环链表的实现
- 【数据结构】双向循环链表实现
- 双向循环链表的C++实现
- C语言实现双向循环链表
- Linux双向循环链表的实现
- 双向循环链表操作的实现
- Linux双向循环链表的实现
- c双向循环链表实现
- shell与C语言
- 【Nginx】利用nginx搭建集群环境
- python3 ZIP文件密码破解
- Ubuntu禁用触摸板
- 线性表综合实验之间接寻址
- 双向循环链表实现大数四则运算
- KMP算法 next与nextval的求解
- JavaScript实现存款利息计算器
- Map集合
- 全局指针的定义
- scala的intersect的一种应用场景
- 让sourceinsight支持查看makefile、kconfig以及.s代码的方法
- 快速排序
- 【面向JS--apply、call、bind】