在一些题目中会出现数据输入很大的情况,如果我们运用不好读取数据工具的话,那么很可能会在读取数据上花费较多的时间,甚至还没读完就超时了。
读取速度
cin << scanf ≈ cin(关闭流同步) << getchar()
cin(关闭流同步)
为什么scanf的读入数据的能力大于cin(未关闭流同步)?
C++中,cin和cout要默认与stdio同步。在cin、cout输入输出下,会有进行缓冲同步stdio,使scanf()与printf()能够与cin、cout混用,也导致cin,cout语句输入输出缓慢。
cin关闭流的同步,就能够实现使用cin、cout输入输出提速的效果(此时效果与scanf()、printf()差不多)。
std::ios::sync_with_stdio(false);
当未关闭流同步时,使用cin读取一千万个整数用了9.52秒。
当关闭流同步后,使用cin读取一千万个整数仅仅用了2.082秒。
读取效率得到了显著提高.
//关闭流同步
//data.txt中有一千万个整数
#include<bits/stdc++.h>
const int MAXN = 10000000;
int numbers[MAXN];
int main()
{
int start = clock();
std::ios::sync_with_stdio(false);
freopen("data.txt","r",stdin);
for (int i=0;i<MAXN;i++)
std::cin >> numbers[i];
std::cout<<double(clock()-start)/CLOCKS_PER_SEC;
return 0;
}
当关闭流同步利弊:
利:在输入n6级别的数据量情况下,相对于未关闭流同步的cin,关闭流的cin输入效率得到提高。
弊:使用scanf()和printf()、getchar()来进行输入或输出的话,会造成输入、输出混乱的情况。
进一步提升效率
在cout和cin两者同时使用的情况下,cin与cout需要交替操作,中间会有一个flush过程,会造成时间消耗。通过 cin.tie(0) 解除cin与cout的绑定,使flush过程不再执行(注意cout没有tie方法)。另外,使用了endl之后,会对缓冲区执行清空操作。endl会先执行’\n’,再执行flush操作,非常漫长,所以尽量使用‘\n’而不是endl执行换行。
当关闭流同步后并解除cin与cout的绑定,使用cin读取一千万个整数用了1.981秒。
//解除
//data.txt中有一千万个整数
#include<bits/stdc++.h>
const int MAXN = 10000000;
int numbers[MAXN];
int main()
{
std::cin.tie(0);
int start = clock();
std::ios::sync_with_stdio(false);
freopen("data.txt","r",stdin);
for (int i=0;i<MAXN;i++)
std::cin >> numbers[i];
std::cout<<double(clock()-start)/CLOCKS_PER_SEC;
return 0;
}
参考文章
关于std::ios::sync_with_stdio(false)
【输入】极速读取
getchar()
事实上,计算机处理char类型变量的速度会快于处理int类型变量。正好可以利用这点将输入再进行一次提速。
下面提供一个简易的快读模板
//快读:读取一个整数
//getchar读取效率比cin、scanf要高
int getInt()
{
char ch = getchar();
int x=0, f=1;
//符号位
while(ch<'0' || ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while('0'<=ch && ch<='9')
{
x = x*10+ch-'0';
ch=getchar();
}
return x*f;
}
希望将自己的学习经验分享给有需要的人。
我是小郑,一个坚持不懈的小白