算法竞赛入门经典(第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、通过http://blog.csdn.net/no_retreats/article/details/7853066研究了substr的用法:
string a=s.substr(0,5); //获得字符串s中 从第0位开始的长度为5的字符串//默认时的长度为从开始位置到尾
8、通过http://blog.csdn.net/nancy_m/article/details/7583550研究了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:50
using 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;
}