输入输出优化

输入输出优化

  (C++) 库里有很多种输入与输出方式,我们最常用的是 (scanf)(printf)(cin)(cout) 。除此之外,其它常见的还有: (getchar)(putchar)(gets)(puts)(fgets)(fputs)(getline) 等等。当输入或输出的数据量过大时,选择效率更高的输入与输出方式将为我们的程序运行节省不少时间。

基本原理

  一般来说,在输入的效率方面,有 (cin lt lt scanf lt cin(关闭同步流) lt getchar) ,具体情况还要看评测环境。不过, (getchar) 的效率往往比 (cin)(scanf) 高得多,因此,基于 (getchar)(putchar) 的输入输出优化应运而生。

效率分析

  在绝大多数情况下,普通的输入输出优化已足以解决问题。然而,依然有极少数的题目会卡掉普通的输入输出优化。这时,需要使用比 (getchar)(putchar) 更快的 (fread)(fwrite)

核心代码

整数

  整数的输入输出优化。

template<class T>inline bool read(T &x)
{
    x=0;register char c=getchar();register bool f=0;
    while(!isdigit(c)){if(c==EOF)return false;f^=c=='-',c=getchar();}
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
    return true;
}
template<class T>inline void print(T x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar(x%10^48);
}
template<class T>inline void print(T x,char c){print(x),putchar(c);}

浮点数

  浮点数的输入输出优化。

template<class T>inline bool readd(T &x)
{
    register ll X=0;register double y=1.0;register char c=getchar();register bool f=0;
    while(!isdigit(c)){if(c==EOF)return false;f^=c=='-',c=getchar();}
    while(isdigit(c))X=(X<<3)+(X<<1)+(c^48),c=getchar();
    x=X;
    if(c!='.'&&c!='E'&&c!='e'){if(f)x=-x;return true;}
    if(c=='.'){c=getchar();while(isdigit(c))x+=(y/=10)*(c^48),c=getchar();}
    if(f)x=-x;
    X=0;f=0;
    if(c=='E'||c=='e')
    {
        c=getchar();
        while(!isdigit(c)){if(c==EOF)return true;f^=c=='-',c=getchar();}
        while(isdigit(c))X=(X<<3)+(X<<1)+(c^48),c=getchar();
    }
    if(f)for(register ll i=1;i<=X;i++)x/=10;
    else for(register ll i=1;i<=X;i++)x*=10;
    return true;
}
template<class T>inline void printd(T x,ll y)
{
    static ll mul[]={1};
    for(register ll i=1;i<=18;i++)
        mul[i]=(mul[i-1]<<3)+(mul[i-1]<<1);
    if(x<-1e-12)putchar('-'),x=-x;
    x*=mul[y];
    register ll x1=(ll)round(x),x2=x1/mul[y],x3=x1-x2*mul[y];
    print(x2);
    if(y>0)
    {
        putchar('.');
        for(register ll i=1;i<y&&x3*mul[i]<mul[y];putchar('0'),i++);
        print(x3);
    }
}
template<class T>inline void printd(T x,ll y,char c){printd(x,y),putchar(c);}

字符

  字符的输入输出优化。

template<class T>inline bool readc(T &x)
{
    register char c=getchar();
    while(c==' '||c=='
'||c=='
'||c=='	')c=getchar();
    if(c==EOF)return false;
    x=c;
    return true;
}
template<class T>inline void printc(T x){putchar(x);}
template<class T>inline void printc(T x,T c){printc(x),putchar(c);}

字符数组

  字符数组的输入输出优化。

template<class T>inline bool readcc(T *x)
{
    register char c=getchar();
    while(c==' '||c=='
'||c=='
'||c=='	')c=getchar();
    if(c==EOF)return false;
    while(c!=' '&&c!='
'&&c!='
'&&c!='	'&&c!=EOF)*x++=c,c=getchar();
    *x=0;
    return true;
}
template<class T>inline void printcc(T *x){while(*x)putchar(*x++);}
template<class T>inline void printcc(T *x,T c){printcc(x),putchar(c);}

字符串

  字符串的输入输出优化。

template<class T>inline bool reads(T &x)
{
    x="";register char c=getchar();
    while(c==' '||c=='
'||c=='
'||c=='	')c=getchar();
    if(c==EOF)return false;
    while(c!=' '&&c!='
'&&c!='
'&&c!='	'&&c!=EOF)x+=c,c=getchar();
    return true;
}
template<class T>inline void prints(T x){for(register ll i=0;x[i]!='';i++)putchar(x[i]);}
template<class T>inline void prints(T x,char c){prints(x),putchar(c);}

加强版

  基于 (fread)(fwrite) 的输入输出优化。需要注意的是,在使用此优化后,只有读到文件末尾才会停止输入,如果使用键盘输入数据,则需要手动添加 (EOF) (在 (Windows) 系统下, (EOF) 手动输入是按 (Ctrl+z) ;在 (Ubuntu) 系统下, (EOF) 手动输入是按 (Ctrl+d) )。

#define getchar gc
#define putchar pc
inline char gc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
static char buf[100000],*pp=buf;
template<class T>inline void pc(T c)
{
    if(pp-buf==100000)fwrite(buf,1,100000,stdout),pp=buf;
    *pp++=c;
}
inline void fsh(){fwrite(buf,1,pp-buf,stdout);pp=buf;}
int main()
{
    return fsh(),0;
}

进阶版

  有时我们需要输入或输出多个同类型数据,而每次仅输入或输出一个数据会使得代码繁琐,此时 (Variadic) (templates) —— (可变模版) 便派上了用场。
  需要注意的是,其仅可在开启 (-std=c++11)(-std=gnu++11) 的环境下使用,并且在多数据输出时会牵扯到繁琐的格式问题,所以在使用时应根据需求修改格式。
  因此并不推荐使用多数据输出。

template<class T,class ...S>inline bool read(T &x,S &...y){return read(x)&&read(y...);}
template<class T,class ...S>inline bool readd(T &x,S &...y){return readd(x)&&readd(y...);}
template<class T,class ...S>inline bool readc(T &x,S &...y){return readc(x)&&readc(y...);}
template<class T,class ...S>inline bool readcc(T *x,S *...y){return readcc(x)&&readcc(y...);}
template<class T,class ...S>inline bool reads(T &x,S &...y){return reads(x)&&reads(y...);}
template<class T,class ...S>inline void print(T x,S ...y){print(x),putchar(' '),print(y...);}
template<class T,class ...S>inline void printd(T x,S ...y){printd(x),putchar(' '),printd(y...);}
template<class T,class ...S>inline void printc(T x,S ...y){printc(x),putchar(' '),printc(y...);}
template<class T,class ...S>inline void printcc(T *x,S *...y){printcc(x),putchar('
'),printcc(y...);}
template<class T,class ...S>inline void prints(T x,S ...y){prints(x),putchar('
'),prints(y...);}

  特别提醒:在使用多数据输出时,除了printc()外,其他所有输出函数行末不会出现多余字符。而对于printc(),其会吞掉最后两个数据间的字符,因此在使用时可以在函数最后额外输出一个' '换行符。
  另外,经过测试,几乎所有的在线 (OJ) 都支持此用法,大部分常见 (OJ) 使用 (C++)(G++) 均可成功编译,只有少数不常见的 (OJ) 需特别使用 (C++11)

原文地址:https://www.cnblogs.com/LengYun/p/11449407.html