标签:方法 ring wap 类型转换 dig rhs 中间 对象 初始
大整数运算的List 采用了双向链表、构造方法
参考:双向链表(C++)
string s = "12"; int a = atoi(s.c_str());
#include <iostream> #include<iomanip> using namespace std; int main() { int a; cin>>a; cout<<setw(3)<<setfill(‘0‘)<<a<<endl; return 0; }
大整数除法则用,补0法
#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