算法竞赛入门经典(第2版) 第5章C++与STL入门

大整数类BigInteger

跟踪调试后的感悟。

1、=(long long num)该赋值方式实际运用价值不大,输入数据一长容易越界。=(const string& str)赋值方式极具实用价值,只要string不越界,就可以处理该整数。

2、将大整数分块处理,BASE=100000000,WIDTH=8,每八位数为一个单元,进行处理:第一个八位数据的得来,num%BASE;下一个8位数据,num/=BASE;num%BASE;依此类推。

3、此类问题的核心在于四则运算的处理,在看代码之前,猜测,加法难在进位的处理,即不同单元数据衔接(每8位为一个单元),故应从低位向高位处理。

4、函数处理过程中,BigInteger引用&的目的是为使避免不必要的值被复制。

5、每个单元选择8位数理由:32位整数-2^31~2^31-1即-2147483648~2147483647,八位数相加包括进位,最多9位数,没有超过上述整数范围,故本程序,如果只处理加法,极限可以考虑到BASE=1000000000,WIDTH=9。经测试验证通过。

6、四则运算,经跟踪,发现不同单元中进位联系完全靠变量g,程序在此处处理得十分巧妙。

7、通过研究了substr的用法:

string a=s.substr(0,5);       //获得字符串s中 从第0位开始的长度为5的字符串//默认时的长度为从开始位置到尾

8、通过研究了c_str()的用法:

 

c_str() 以 char* 形式传回 string 内含字符串
如果一个函数要求char*参数,可以使用c_str()方法: 
string s = "Hello World!";
printf("%s", s.c_str()); //输出 "Hello World!"

9、通过http://blog.sina.com.cn/s/blog_7b3a697301014a9n.html学习了vector中back()的用法:

返回当前vector容器中末尾元素的引用。

10、力争能独立编码,该代码阅读比想象的要复杂。

11、基本处理思路,从低位向高位处理。如12345678909876543210按如下方式存储于数组中:

s[0]=76543210 s[1]=56789098 s[2]=1234

12、将operator =,operator +放入BigInteger类中,可以减少只用一个参数,另一个默认参数是该类的实例。若放类外部,则要用两个参数。

13、len=(str.length()-1)/WIDTH+1;技巧如下,若有32位,分成(32-1)/8+1=4块;若有31位,分成(31-1)/8+1=4块;若有33位,分成(33-1)/8+1=5块,所有情况通吃,好技巧。

14、vector元素访问可以参考数组,但赋值处理只能用push_back,若用v[i]=x%BASE;会报错,只能用v.push_back(x%BASE);

15、BigInteger分析暂告一段落,已将核心代码研究了,等功力深厚了,再回过头来研究。

 

附上代码:

#include <iostream>
 #include <vector>
 #include <string>
 #include <cstdio>//漏了此句,noi linux下,报错,sscanf,sprintf 未申明 2019-2-16 21:50using namespace std;
struct BigInteger{
     static const int BASE=100000000;
     static const int WIDTH=8;
     vector<int> v;
     
     BigInteger operator = (const string& s){
         int x;
         int start;
         int end;
         int i;
         int blocks;
         blocks=(s.length()-1)/WIDTH+1;
         for(i=0;i<blocks;i++){
             end=s.length()-i*WIDTH;
             start=max(0,end-WIDTH);
             sscanf(s.substr(start,end-start).c_str(),"%d",&x);//原来写成sscanf(s.substr(start,end).c_str(),"%d",&x);在NoMore549帮助下改正 2019-2-16 21:53
             v.push_back(x);
         }
         
         return *this;
     }
     
     BigInteger operator + (const BigInteger &b){
         BigInteger c;
         int i,g;
         int x;
         for(i=0,g=0;;i++){
             if(g==0&&i>=v.size()&&i>=b.v.size()){//无进位,两个BigInteger实例均已遍历完成
                 break;
             }
             x=g;
             if(i<v.size())
                 x+=v[i];
             if(i<b.v.size())
                 x+=b.v[i];
             c.v.push_back(x%BASE);
             g=x/BASE;
         }
         return c;
     }};
istream& operator >> (istream &in, BigInteger &b){
     string x;
     in>>x;
     b=x;
     return in;
 }ostream& operator << (ostream &out,const BigInteger &b){
     int i;
     char buf[20];
     out<<b.v.back();//最高位不足8位的预防处理
     for(i=b.v.size()-2;i>=0;i--){
         sprintf(buf,"%08d",b.v[i]);//不足8位补0
         cout<<buf;
     }
     return out;
 }
 int main(){
     BigInteger a,b;
     cin>>a>>b;
     cout<<a+b<<endl;
     return 0;
 }