一、背景
这是某道题目的状态:
我的代码:
大牛的代码:
我瞬间萌币了!
我有这么慢?Are you kidding me?
点进去一看:
[cpp] view plain copy print?
void Read(int & p)
{
p=0;
int flag=1;
char c=getchar();
while(c<'0' or c>'9')
{
if(c=='-') flag=-1;
c=getchar();
}
while(c>='0' and c<='9')
p=p*10+(c-'0'),c=getchar();
p*=flag;
}
这是什么?
原来,这是读入优化啊!
二、读入优化的原理与实现
C语言和C++库里有很多种输入方式,我们最常用的是scanf和cin。除此之外,还有:
char c[]; gets(c);//读入一行字符串,但是需要注意的是,它只会在遇到’\n’后停止,不会因为超过c的内存上限而停止。所以容易溢出。
char c[]; fgets(c,len,stdin);//读入一行字符串。和gets不同的是,它如果读入了len-1个字符,就会停止。
char c=getchar();//就像scanf一样,只读入一个字符,并返回这个字符,需要#include头文件。与scanf不同的是,它没有缓冲,也就意味着它会更快。
char c=getch();//直接读入一个字符,而不会回显。也就是说,你读入了一个字符,它不会在界面里显现而直接读入getch,getch也会直接返回这个字符。比如说你写了一个程序小游戏,你肯定不希望看到wasdwasdwasd满天飞,所以就用getch。需要#include
[cpp] view plain copy print?
int Read()
{
int p=0;
char c=getchar();
while(c<'0' or c>'9') c=getchar();
while(c>='0' and c<='9')
p=p*10+(c-'0'),c=getchar();
return p;
}
调用p=Read();即可。
其实(c>=’0’ and c<=’9’)也是一个函数isdigit(c),如果c是代表数字的字符,就返回1,否则返回0,需要#include头文件。
所以也可以写成:
[cpp] view plain copy print?
void Read(int & p)
{
p=0;
char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c))
p=p*10+(c-'0'),c=getchar();
}
的形式。
三、整数读入优化的特殊处理——负数
对于一个负数,读入优化只会读入数字,负号并不会被读入。
所以需要读入负数,要特判这个字符是不是负号,如果是,那么这个值要改成负数。
这就是文章开头的代码:
[cpp] view plain copy print?
void Read(int & p)
{
p=0;
int flag=1;
char c=getchar();
while(c<'0' or c>'9')
{
if(c=='-') flag=-1;
c=getchar();
}
while(c>='0' and c<='9')
p=p*10+(c-'0'),c=getchar();
p*=flag;
}
但是,这个代码有一个弊端。所有的‘-’都必须代表负号。如果是减号,比如4-3,就会读错。
四、验证读入优化的效率
用freopen生成五百万个数的文本,并分别用scanf,cin和读入优化读入。
文本生成:
[cpp] view plain copy print?
#include
int main()
{
freopen("test.txt","w",stdout);
const int N=5000000;
for(int i=1;i<=N;i++)
printf("%d ",N);
}
验证程序:
[cpp] view plain copy print?
#include
#include
#include
#include
#include
#include
using namespace std;
void s(int & p)
{
scanf("%d",&p);
}
void c(int & p)
{
cin>>p;
}
void Read(int & p)
{
p=0;
char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c))
p=p*10+(c-'0'),c=getchar();
}
double t1,t2;
int main()
{
freopen("test.txt","r",stdin);
int p;
t1=clock();
//for(int i=1;i<=5000000;i++) s(p);
//for(int i=1;i<=5000000;i++) c(p);
for(int i=1;i<=5000000;i++) Read(p);
t2=clock();
//printf("scanf took %.2lf second",(t2-t1)/1000);
//printf("cin took %.2lf second",(t2-t1)/1000);
printf("Read took %.2lf second",(t2-t1)/1000);
}
结果:
scanf took 0.85 second
cin took 14.63 second
Read took 0.35 second
所以说读入优化还是很快的。