码迷,mamicode.com
首页 > 其他好文 > 详细

大整数运算

时间:2018-12-06 17:46:33      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:方法   ring   wap   类型转换   dig   rhs   中间   对象   初始   

大整数运算的List 采用了双向链表、构造方法

参考:双向链表(C++)

      C++ string转int

string s = "12"; 
int a = atoi(s.c_str());

 

   C++ cout输出指定位数 不足补0

#include <iostream>
#include<iomanip>
using namespace std;

int main()
{
 int a;
 cin>>a;
 cout<<setw(3)<<setfill(0)<<a<<endl;
 return 0;
}

 

  C++ string的截取、替换、查找子串

      C++拷贝构造,赋值构造

 

     大整数乘法

    大整数除法则用,补0法

   C/C++ 程序运算时间

#include<iostream.h>
#include<time.h>
void main()
{
   clock_t start,finish;
   double totaltime;
   start=clock();

   ……                     //把你的程序代码插入到这里面

   finish=clock();
   totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
   cout<<"\n此程序的运行时间为"<<totaltime<<"秒!"<<endl;
}

 

 

 

 

 

 List.h

#ifndef LIST_H_
#define LIST_H_

#include<iostream>

using namespace std;

struct Node{ //节点类
    Node* pre; //前驱指针
    Node* next; //后继指针
    int data; //节点的数据
    
    Node(const int x);
};

class List{ //链表类
public:
    List();
    List(const List& s);
    List& operator=(const List& s);
    ~List();

    friend const List operator+(const List& ths, const List& lhs);
    friend const List operator-(const List& ths, const List& lhs);
    friend const List operator*(const List& ths, const List& lhs);
    friend const List operator/(const List& ths, const List& lhs);
    friend const List operator^(const List& ths, const List& lhs);
    
public:
    void Reverse();
    void Print();
    void Print_sub();
    void Print_dig();
    void Push(const int& x);
    int Amount() const; //因为在减法的时候,要调用,且参数是const传入,所以要加Amount() const 保证Amount函数不会修改成员变量
    int Digit() const;
    
private:
    Node* first;
    Node* last;
};

 

List.cpp

#include<iostream>
#include<utility> //swap
#include<iomanip> //setw swtfill
#include"List.h"

using namespace std;

Node::Node(const int x):data(x),next(NULL),pre(NULL){}

List::List():first(NULL),last(NULL){}

List::List(const List& s):first(NULL),last(NULL){
    if(s.first == NULL){
        return;
    }
    Node* tmp = s.first;
    while(tmp){
        this->Push(tmp->data);
        tmp = tmp->next;
    }
}

List::~List(){
    while(first){
        Node* tmp = first->next;
        delete first;
        first = tmp;
    }
    first = NULL;
    last = NULL;
}

void List::Push(const int& x){
    if(first==NULL){ //当是空链表时
        first = new Node(x);
        last = first;
    }
    else{
        last->next = new Node(x);
        last->next->pre = last; //新添加的结点的pre设置
        last = last->next;
        last->next = NULL;
    }
}

//双向链表的逆转
void List::Reverse(){
    
    //头,尾结点不能是空
    if(first==NULL || last==NULL){
        return ;
    }
    int ret = Amount();
    
    //从头尾交换,向中间靠拢。交换的事结点的值
    Node* begin=first;
    Node* end=last;
    while(ret){
        if(end->next == begin) break; //当结点个数是偶数个的跳出结果,从last的结点在 first来的结点之前时,跳出循环
        ret/=2; //当结点个数是奇数的跳出结果
        swap(begin->data,end->data);
        begin = begin->next;
        end = end->pre;
    }
}

//赋值构造函数
List& List::operator=(const List& s){
    
    //不能出现自己给自己赋值的情况,没有任何意义
    if(this!=&s){
        Node* tmp = s.first;
        
        //清空原链表的值
        Node* t = this->first;
        while(t){
            Node* c = t;
            t = t->next;
            delete c;
        }
        this->first = this->last = NULL;
        
        
        while(tmp){
            this->Push(tmp->data);
            tmp=tmp->next;
        }
    }
    return *this;
}


//输出加,乘
void List::Print(){
    if(first==NULL){
        cout << "This List is Empty!" << endl;
        return;
    }
    else{
        Node* begin=first;
        
        //只有一个结点
        if( first->next == NULL){
            cout<< begin->data << endl;
        }
        else{
            int flag=0; //最高位
            
            
            while(begin->next){//如果是最后一个结点不用输出逗号
                if(!flag){
                    cout  << begin->data << ",";
                    flag=1;
                }
                else{
                    cout << setw(3) << setfill(0) << begin->data << ",";
                }
                begin = begin->next;
            }
            cout << setw(3) << setfill(0) << begin->data << endl;
        }
    }
}


//输出负数,除数
void List::Print_sub(){
    if(first==NULL){
        cout << "This List is Empty!" << endl;
        return;
    }
    else{
        Node* begin = first;
        int flag_1 = 0; //判断高位什么时候不是零
        int flag_2 = 0; //判断是不是首位
        
        //负数
        if( first->data == -1 ){
            cout << "-";
            begin = begin->next;
        }
        
        //个位数后无逗号
        while(begin->next){
            
            //结点的值是不是0
            if( begin->data != 0 ){
                
                //如果是首位,则不用扩充添0
                if( !flag_2 ){
                    cout << begin->data << ",";
                    flag_2 = 1;
                }
                else{
                    cout << setw(3) << setfill(0) << begin->data << ",";
                }
                flag_1 = 1;
            }
    
            //结点的值是0
            else{
                if( flag_1 ){ //最高位不是0
                    if( !flag_2 ){  //是最高位
                        cout << begin->data << ",";
                        flag_2 = 1;
                    }
                    else{
                        cout << setw(3) << setfill(0) << begin->data << ",";
                    }
                }
            }
            begin = begin->next;
        }
        
        //个位数
        if( begin->pre == NULL ){
            cout << begin->data << endl;
        }
        
        //不是个位数,输出最后一个结点的值
        else{
            if( !flag_2 ){
                cout << begin->data << endl ;
            }
            else{
                cout << setw(3) << setfill(0) << begin->data << endl;
            }
        }
    }
}

//输出位数
void List::Print_dig(){
    cout << this->Digit() << endl;
}

//结点个数
int List::Amount() const{
    if(first == NULL){
        return 0;
    }
    else{
        int count=0;
        
        Node* tmp = first;
        while(tmp){
            count++;
            tmp=tmp->next;
        }
        return count;
    }
}

//位数
int List::Digit() const{ 
    int d=this->Amount();
    int count=0; //计算0在高位的个数
    Node* t = this->first;
    
    //如果是负数,将负数标志略过
    if( t->data==-1 ){
        t = t->next;
        d -= 1;
    }
    
    //非零最高位,除非该数就是0
    while( t->data==0 ){
        if( t->next!=NULL ){ //
            t = t->next;
            count++;
        }
        else{
            break;
        }
    }
    
    //判断最高位处于的结点处,是一位,两位还是三位数
    d -= count;
    if( t->data<10 ){
        d = d*3-2;
    }
    else if( t->data<100 ){
        d = d*3-1;
    }
    else{
        d = d*3;
    }
    
    return d;
}

List const operator+(const List& ths, const List& lhs){
    List* tmp = new List;
    Node* begin_1 = ths.first;
    Node* begin_2 = lhs.first;
    int data=0; //进位标志
    while(begin_1 && begin_2){
        int cur=begin_1->data + begin_2->data + data;
        if(cur>=1000){
            data = 1;
            cur -= 1000;
        }
        else{
            data = 0;
        }
        tmp->Push(cur);
        begin_1 = begin_1->next;
        begin_2 = begin_2->next;
    }
    
    //将多余的加数,下放到结果
    if(begin_1){
        while(begin_1){
            int cur = begin_1->data+data;
            if(cur>=1000){
                data = 1;
                cur -= 1000;
            }
            else{
                data = 0;
            }
            tmp->Push(cur);
            begin_1 = begin_1->next;
        }
    }
    else if(begin_2){
        while(begin_2){
            int cur = begin_2->data+data;
            if(cur>=1000){
                data = 1;
                cur -= 1000;
            }
            else{
                data = 0;
            }
            tmp->Push(begin_2->data);
            begin_2 = begin_2->next;
            
        }
    }
    
    //最高位还有进位
    else if(data==1){
        tmp->Push(data);
    }
    return *tmp;
}


List const operator-(const List& lhs, const List& rhs){
    List* tmp = new List;
    Node* begin_3 = lhs.last;
    
    //在除法的时候,会出现最高位是0的情况,所以要取被减数的非零最高位
    while( begin_3->data==0 ){
        if( begin_3->pre != NULL ){ //为了防止出现 lhs就是0的情况,且发现一个 NULL的结点是没有pre和next的 无法访问
            begin_3 = begin_3->pre;
        }
        else{
            break;
        }
    }
    
    Node *begin_1 = nullptr;
    Node *begin_2 = nullptr;
    int flag_1=0; //判断结果是不是负数
    int flag_2=0; //判断结果是不是0

    //始终保持是大数减小数,当出现被减数位数较小时,则添加负数标志
    if( lhs.Amount() > rhs.Amount() ){
        begin_1 = lhs.first;
        begin_2 = rhs.first;
    }
    else if( lhs.Amount() < rhs.Amount()){
        begin_1 = rhs.first;
        begin_2 = lhs.first;
        flag_1 = 1;
    }
    
    //当位数相同时,不断从高位开始比较大小,若相同,则不断向前遍历,直到能比较出大小,若个位也相同,则添加结果为0标志
    else{
        Node* t1 = lhs.last;
        Node* t2 = rhs.last;
        while( t1 ){
            if( t1->data > t2->data ){
                begin_1 = lhs.first;
                begin_2 = rhs.first;
                break;
            }
            else if( t1->data < t2->data ){
                begin_1 = rhs.first;
                begin_2 = lhs.first;
                flag_1 = 1;
                break;
            }
            else{
                t1 = t1->pre;
                t2 = t2->pre;
            }
        }
        if(t1==NULL){
            flag_2 = 1;
        }
    }
    
    
    if(flag_2){ //判断结果是不是0
        tmp->Push(0);
    }
    else{
        int c=0;//借位标志
        
        
        while(begin_2){
            int cur = begin_1->data-c; //被减数被借位后的结果
            c = 0;
            
            //减数大于被减数
            if( begin_2->data > begin_1->data ){
                
                //当减数大于被减数,且已经减到最高位,则添加负数标志
                if( begin_1 == begin_3 ){
                    tmp->Push( begin_2->data - begin_1->data);
                    flag_1=1;
                }
                
                //还未减到最高位
                else{
                    c = 1;
                    //begin_1->data += 1000; //在这里因为Node指向链表的结点所以+=修改了结点的值,即lhs的结点值改变了
                    tmp->Push( (cur+1000) - begin_2->data );
                }
            }
            else{
                tmp->Push( (cur) - begin_2->data );
            }
            begin_1 = begin_1->next;
            begin_2 = begin_2->next;
        }

        //将多余的减数,下放到结果
        if( begin_1!=begin_3->next ){
            while( begin_1!=begin_3->next ){
                int cur = begin_1->data-c; //被借位后的值
                c=0;
                
                //小于0则借位
                if( cur<0 ){
                    tmp->Push(cur+1000);
                    c=1;
                }
                
                //等于0,判断是不是最高位
                else if( cur==0 ){
                    if( begin_1 != begin_3){
                        tmp->Push(cur);
                    }
                }
                else{
                    tmp->Push( cur );
                }
                begin_1 = begin_1->next;
            }
        }
        
        if(flag_1){
            tmp->Push(-1);
        }
    }
    
    
    return *tmp;
}


List const operator*(const List& lhs, const List& rhs){
    List* tmp =new List;
    int *a;
    int *b;
    int lAmount=lhs.Amount();
    int rAmount=rhs.Amount();
    
    //乘数和被乘数出现0,结果直接为0
    if( (lAmount==1 && lhs.first->data == 0) || (rAmount==1 && rhs.first->data == 0)){
        tmp->Push(0);
    }
    
    //采用数组存储的方式,小数存于数组a,大数存于数组b
    else{
        
        //如果被乘数大于乘数,进行交换
        if( lhs.Amount() > rhs.Amount() ){
            int t=0;
            t = lAmount;
            lAmount = rAmount;
            rAmount = t;
        }
        
        //构造a,b
        if( lhs.Amount() <= rhs.Amount() ){
            a = new int[lAmount];
            Node* begin_1 = lhs.first;
            b = new int[rAmount];
            Node* begin_2 = rhs.first;
            for(int i=lAmount-1; i>=0; i--){
                a[i] = begin_1->data;
                begin_1 = begin_1->next;
            }
            for(int i=rAmount-1; i>=0; i--){
                b[i] = begin_2->data;
                begin_2 = begin_2->next;
            }
        }
        else{
            a = new int[lAmount];
            Node* begin_1 = rhs.first;
            b = new int[rAmount];
            Node* begin_2 = lhs.first;
            for(int i=lAmount-1; i>=0; i--){
                a[i] = begin_1->data;
                begin_1 = begin_1->next;
            }
            for(int i=rAmount-1; i>=0; i--){
                b[i] = begin_2->data;
                begin_2 = begin_2->next;
            }
        
        }
        
        
        int c=0,d=0;
        int *k = new int[lAmount+rAmount];
        int count=0;
        for(int i = lAmount + rAmount -2; i>=0; i--){
            c=d; //将前一位的进位标志存入累加变成c
            int ma = (i-rAmount+1)>0?(i-rAmount+1):0; //求累加的下限
            int mi = lAmount<=i?(lAmount-1):i; //求累加的上限
            
            for(int j=ma; j<=mi; j++){
                c+=a[j]*b[i-j];
            }
            d = c/1000; //求进位标志
            if(c>999) c %= 1000; //取c的后3位
            k[count++]=c; //保存至表示乘积的数组k[]
        }
        
        
        if( d!=0 ){ //出现最高位进位
            k[count] = d;
        }
        else{
            count--; //因为没有进位 位数大小-1;
        }
        
        for(int i=0; i<=count; i++){
            tmp->Push(k[i]);
        }
    }
    
    return *tmp;
}


//结点指针指向了同一块区域 就是-=的问题 然后内存上好像好像运算越少越好,且不要构造出新的对象
List const operator/(const List& lhs, const List& rhs){
    List* tmp = new List;
    
    //如果被除数小于除数,则结果是0
    if( lhs.Amount()<rhs.Amount() ){
        tmp->Push(0);
    }
    
    //除数是1,则直接输出被除数
    else if( rhs.Amount()==1 && rhs.first->data==1 ){
        Node* b1 = lhs.first;
        while(b1){
            tmp->Push(b1->data);
            b1 = b1->next;
        }
    }
    
    //除数与被除数的位数相同,直接相减,直到被减数变为负数为止
    else if( lhs.Amount()==rhs.Amount() ){
        int count=0;
        List t = lhs;
        do {
            t = t-rhs;
            if( t.last->data != -1 ){
                count++;
            }
            else{
                break;
            }
        } while ( 1 );
        tmp->Push(count);
    }
    
    //被除数位数大于除数
    else{
        int c = lhs.Amount() - rhs.Amount(); //判断差几个结点,即几个10^3
        tmp->Push(0);
        List t1 = lhs;
        
        //采用放大减法。直到位数相同
        while( c>=0 ){
            List temp;
            List t=rhs;
            
            //因为存储first是个位,所以放大添0,要逆转将last变成个位
            t.Reverse();
            for( int i=0; i<c; i++){
                t.Push(0);
                temp.Push(0); //结果的倍数
            }
            t.Reverse(); //复原
            
            int count=0;
            List p=t1;
            int tp; //非零最高位,被减为0,则退出循环
            
            do {
                Node* cur = t1.last;
                
                //如果被除数为0,则直接退出循环
                if( t1.last == t1.first && t1.first->data==0 ){
                    break;
                }
                
                //cur为非零最高位的结点
                while( cur->data <= 0){
                    cur = cur->pre;
                }
                tp = cur->data;

                //当减为负数时时,退出循环
                p = t1-t;
                if( p.last->data != -1 ){
                    count++;
                    t1=t1-t;
                    tp = tp - t.last->data;
                }
                else{
                    break;
                }
            } while ( tp!=0 );

            //累加结果
            temp.Push(count);
            *tmp = *tmp+temp;
            c--;
        }
    }

    return *tmp;
}

List const operator^( const List& lhs, const List& rhs ){
    List tmp; //结果
    tmp.Push(1); //将结果初始值制为1
    List tmp2 = lhs; //被乘数
    int cur=rhs.last->data; //取末尾数
    int r=0; //余数
    //为了判断是不是2的倍数,从而进行累乘
    if( cur%2 ){
        r = cur%2;
        cur=cur-r;
    }

    int i=0;
    while( cur ){
        cur -= i; //判断还需剩余循环几次
        i = 2;
        List tmp3 = lhs;
        for( ; i<=cur; i*=2 ){
            tmp3 = tmp3*tmp3;
        }
        i /= 2;
        if( i!=1 ){ //如果cur是0,则不乘
            tmp = tmp*tmp3;
        }
    }
    if( r ){ //如果累次是奇数
        tmp = tmp*lhs;
    }
    return tmp;
}

 

 

bigint.h

#ifndef BIGINT_H_
#define BIGINT_H_

#include<iostream>
#include"List.h"



using namespace std;

class Bigint{
public:
    Bigint();
    Bigint(string s);
    ~Bigint();
    Bigint(Bigint& b);
    void Print();
    void Print_sub();
    void Print_dig();
    
    
    Bigint& operator=(const Bigint& s);
    friend const Bigint operator+(Bigint& ths, Bigint& lhs);
    friend const Bigint operator-(Bigint& ths, Bigint& lhs);
    friend const Bigint operator*(Bigint& ths, Bigint& lhs);
    friend const Bigint operator/(Bigint& ths, Bigint& lhs);
    friend const Bigint operator^(Bigint& ths, Bigint& lhs);
private:
    List* l;
};



#endif

 

bigint.cpp

#include<iostream>
#include<string>
#include"bigint.h"
#include"List.h"

using namespace std;

Bigint::Bigint(){l = new List;}

Bigint::Bigint(string s){
    l = new List;
    unsigned long amount=s.length();
    unsigned long count_1=amount/3;
    unsigned long count_2=amount%3;
    unsigned long c=amount;
    while(count_1--){
        string str;
        str = s.substr(c-=3,3);
        int a = atoi(str.c_str());
        l->Push(a);
    }
    if(count_2){
        string str = s.substr(0,count_2);
        int a = atoi(str.c_str());
        l->Push(a);
    }
}
/*
 
 4
 */


Bigint::~Bigint(){
    delete l;
}

Bigint::Bigint(Bigint& s){
    this->l = s.l;
}

void Bigint::Print(){
    this->l->Reverse();
    this->l->Print();
}

void Bigint::Print_sub(){
    this->l->Reverse();
    this->l->Print_sub();
}

void Bigint::Print_dig(){
    this->l->Print_dig();
}

Bigint& Bigint::operator=(const Bigint &s){
    if(this!=&s){
        List* tmp = new List;
        *tmp = *(s.l);
        this->l = tmp;
    }
    return *this;
}



const Bigint operator+(Bigint& ths, Bigint& lhs){
    Bigint b;
    List* l = ths.l;
    List* l2 = lhs.l;
    *(b.l) = *l+*l2;
    return b;
}

const Bigint operator-(Bigint& ths, Bigint& lhs){
    Bigint b;
    List* l = ths.l;
    List* l2 = lhs.l;
    *(b.l) = *l-*l2;
    return b;
}

const Bigint operator*(Bigint& ths, Bigint& lhs){
    Bigint b;
    List* l = ths.l;
    List* l2 = lhs.l;
    *(b.l) = (*l) * (*l2);
    return b;
}

const Bigint operator/(Bigint& ths, Bigint& lhs){
    Bigint b;
    List* l = ths.l;
    List* l2 = lhs.l;
    *(b.l) = (*l) / (*l2);
    return b;
}

const Bigint operator^(Bigint& ths, Bigint& lhs){
    Bigint b;
    List* l = ths.l;
    List* l2 = lhs.l;
    *(b.l) = (*l) ^ (*l2);
    return b;
}

 

main.cpp

#include<iostream>
#include<time.h>

#include"List.h"
#include"bigint.h"

using namespace std;

int main(){
    clock_t start,finish;
    double totaltime;
    start=clock();
    
    
    string a;
    string b;
    cin >> a;
    cin >> b;
    Bigint x(a);
    Bigint y(b);
    Bigint result;
    
    cout << endl << endl << endl;
    
    start=clock();
    result = x+y;
    finish=clock();
    cout << "+:" << endl;
    result.Print();
    cout << "digit:" << endl;
    result.Print_dig();
    totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
    cout << "time:" << totaltime << "s";
    cout << endl << endl << endl;
    
    start=clock();
    result = x-y;
    finish=clock();
    cout << "-:" << endl;
    result.Print_sub();
    cout << "digit:" << endl;
    result.Print_dig();
    totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
    cout << "time:" << totaltime << "s";
    cout << endl << endl << endl;
    
    start=clock();
    result = x*y;
    finish=clock();
    cout << "*:" << endl;
    result.Print();
    cout << "digit:" << endl;
    result.Print_dig();
    totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
    cout << "time:" << totaltime << "s";
    cout << endl << endl << endl;
    
    start=clock();
    result = x/y;
    finish=clock();
    cout << "/:" << endl;
    result.Print_sub();
    cout << "digit:" << endl;
    result.Print_dig();
    totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
    cout << "time:" << totaltime << "s";
    cout << endl << endl << endl;
    
    start=clock();
    result = x^y;
    finish=clock();
    cout << "^:" << endl;
    result.Print();
    cout << "digit:" << endl;
    result.Print_dig();
    totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
    cout << "time:" << totaltime << "s";
    cout << endl << endl << endl;

}

 

 

总结:

1. 当List作为 bigint类的成员变量时,在析构时,如果成员变量写的是List l,无需写入,而当写的是List* l时,因为在构造时需要new一个list ,因为你只给了一个指针,所以去分配他的内存。

2. 当写了一个Node 等于List中的一个结点时,修改该Node值时,即使List是const,也会被修改。

3.Bigint& operator=(const Bigint& s); //返回类型&是因为需要=可以作为左值,而参数const的原因是,因为在做+的时候,返回类型是const,如果参数不做const会导致类型不匹配,你可以修改,而它却是const不可修改

    friend const Bigint operator+(Bigint& ths, Bigint& lhs);//二目运算作为友元函数,为了可以使得,两个参数都可以做类型转换。 返回类型const是因为需要保证不做左值。

大整数运算

标签:方法   ring   wap   类型转换   dig   rhs   中间   对象   初始   

原文地址:https://www.cnblogs.com/fitzroy343/p/10031588.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!