C++标准库提供了强大的输入输出方法。但是,出于设计与安全上的原因,它们的性能不一定能满足算法竞赛的需求,因此在面对巨大的输入输出文件时可能需要考虑优化。
注意:
- 通常来说,不必特别在意读写优化。
- 如果习惯
cin/cout
的话,在文件较大时记得关闭流同步,使用'\n'
而不是endl
。 - 输入输出文件大小十分极端时,才需要考虑手写读写优化。这通常意味着输入输出文件超过了 \({10}^{6}\) 个
int
,即使在这个量级下,手写输入与标准库的差距仍通常不到0.1s。
当然,可以通过以下代码关闭流同步提升 cin/cout
性能。关闭流同步后,cin/cout
会拥有自己的缓冲区,与 scanf/printf
混用会带来异常。
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cout<<endl;
会使用系统调用刷新输出缓冲区,输出大量换行时非常缓慢。
如果需要手写输入函数,使用getchar读取整数是一个有效减少输入时间的手段。
template<typename T1>
void read(T1 &x){
char c;
c=getchar();
bool flag=1;//是否为正数
while(c<'0'||c>'9'){//在整数前通常有一些其它字符
if(c=='-'){
flag=0;
}
c=getchar();
}
x=0;
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+c-'0';//使用位运算优化x*10
c=getchar();
}
x=flag?x:(-x);
}
注意:
在输入到达文件结束时继续读取,getchar()会返回-1,导致死循环。如果遇到输入可能不完整的情况,需要在第一个while里判断EOF。
上面的程序中 getchar()
仍可以优化。stdio库里维护了一个缓冲区,以减少读取硬盘的次教:我们可以自己调用 fread
,来进一步减少读取硬盘的次数和标准库边界检查的时间。标准库些里通常缓冲区的大小为8KiB,事实上这是一个合理的大小:更大的缓冲区性能提升非常小。我们可以选择稍大一些的2的次幂作为缓冲区的大小。
const int SIZE=1<<14;//16Kib
char getc(){
static char buf[SIZE],*begin=buf,*end=buf;
if(begin==end){
begin=buf;
end=buf+fread(buf,1,SIZE,stdin);
}
return *begin++;
}
使用以上代码中的 getc()
函数替代 getchar()
,可以获得部分性能提升。
如果评测系统为Linux,可以考虑直接使用getchar_unlocked()
替代getchar()
,效率接近fread
。这是一种放弃了线程安全的函数,但是对算法竞赛来说没有弊端。
知道了上述原理,我们就可以写出此题代码了:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0;
bool b=false;
char ch=getchar_unlocked();
while(ch<'0'||ch>'9'){
if(ch=='-') b=true;
ch=getchar_unlocked();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar_unlocked();
}
if(b) return -x;
else return x;
}
int main(){
int n,sum=0;
n=read();
while(n--) sum+=read();
printf("%d\n", sum);
return 0;
}
标签:ch,P10815,cout,cin,while,读入,缓冲区,快速,getchar
From: https://www.cnblogs.com/cly312/p/18417051