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

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

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

除法则枚举答案的每一位,按位更新,复杂度O(n216)O(\frac{n^2}{16})O(16n2)

代码:(详细注释)

#include
#include
#include
#include
#include
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_Integer
bool 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
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

    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;
}


你可能感兴趣的:(大数,高精度,双向循环链表,FFT,牛顿迭代法)