双向循环链表实现大数四则运算

来源:互联网 发布:靠网络赚钱 编辑:程序博客网 时间:2024/06/08 07:10

本学期数据结构课程设计的第一个作业。

初步想法:
使用FFT优化乘法
n为大数的位数。
则乘法复杂度:O(n4log(n4))
(压位处理,其中链表每一个节点存储四位数据)

除法则枚举答案的每一位,按位更新,复杂度O(n216)

代码:(详细注释)

#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;}
原创粉丝点击