输入输出效率对比

输入输出效率对比

前言

在OI竞赛中,几乎每道题都需要进行文件的读写操作。然而在非常紧的时间限制内,读写的时间也至关重要。目前可供使用的标准输入输出操作有如下几种:

  1. cin/cout
  2. cin/cout+取消同步
  3. scanf/printf
  4. 手写I/O优化

那么本文接下来将会对这几种方法进行简单的比较。

介绍

​ 首先对各种输入输出方式给出简单的介绍。

cin/cout

​ 这是C++标准库中提供的对读入输出流进行操作的对象,也是大部分C++程序所使用的读写方式。在流中需要开辟一个缓冲区,此处不过多赘述,但要知道的是这样的处理可以延长内存或者外部存储器的寿命,但这样也使得cin/cout的效率降低。

1
2
cin>>x;
cout<<x

scanf/printf

​ 这是C语言库中提供的格式化读入输出函数,相较于cin/cout要更加底层,效率要好一些,但是缺点是格式比较复杂。

cin/cout+取消同步

​ 在默认情况下,为了保持同C语言程序的兼容性,可以在代码中同时使用cin/cout和scanf/printf两种读写方法。但是如果取消这种同步性,cin/cout的效率会有提高。

使用时只要在代码开始运行时加上这样一句:

1
ios::sync_with_stdio(false);

手写I/O优化

​ 手写读入输出优化是OI竞赛中常见的技巧,对于大量读入或者输出的题目可以大幅提高速度。但是当然对存储器不是很友好,所以一般在其他的程序中不建议使用。

这里给出一种版本的模板:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//读入优化
template<typename T>
void read(T& w) 
{
    char r;int f=1;
    for(r=getchar();(r<48||r>57)&&r!='-';r=getchar());
    if(r=='-')r=getchar(),f=-1;
    for(w=0;r>=48&&r<=57;r=getchar())w=w*10+r-48;
    w*=f; 
}
//输出优化 
template<typename T>
void write(T w)
{
    if(w<0)w=-w;
    if(w==0)putchar('0');
    else 
    {
        if(w>9)
            write(w/10);
        putchar(char(w%10+48));
    }
}

比较

我们采取一种方式对这些读入输出优化进行量化的比较。

读入测试

数据

​ 读入n个随机int类型整数(有正有负)

​ 共8组数据,n(i)=10^(i-1)

程序

以下是进行读入测试的程序:

cin
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
 
int n,x;
int main()
{
    freopen("x.in","r",stdin);
    freopen("x.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cin>>x;
    }
    cout<<n<<endl;
    return 0;
}
cin/sync
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
 
int n,x;
int main()
{
    freopen("x.in","r",stdin);
    freopen("x.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cin>>x;
    }
    cout<<n<<endl;
    return 0;
}
read/template
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
template<typename T>
void read(T& w)
{
    char r;int f=1;
    for(r=getchar();(r<48||r>57)&&r!='-';r=getchar());
    if(r=='-')r=getchar(),f=-1;
    for(w=0;r>=48&&r<=57;r=getchar())w=w*10+r-48;
    w*=f;
}
int n,x;
int main()
{
    freopen("x.in","r",stdin);
    freopen("x.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        read(x);
    }
    cout<<n<<endl;
    return 0;
}
read/int
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
void read(int& w)
{
    char r;int f=1;
    for(r=getchar();(r<48||r>57)&&r!='-';r=getchar());
    if(r=='-')r=getchar(),f=-1;
    for(w=0;r>=48&&r<=57;r=getchar())w=w*10+r-48;
    w*=f;
}
int n,x;
int main()
{
    freopen("x.in","r",stdin);
    freopen("x.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        read(x);
    }
    cout<<n<<endl;
    return 0;
}
scanf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
 
int n,x;
int main()
{
    freopen("x.in","r",stdin);
    freopen("x.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&x);
    }
    cout<<n<<endl;
    return 0;

输出测试

数据

读入n,对于所有1<=i<=n,按顺序输出i,-i;

n[i]=10^(i-1)

程序

cout
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
 
int n,x;
int main()
{
    freopen("y.in","r",stdin);
    freopen("y.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cout<<i<<endl;
        cout<<-i<<endl;
    }
    return 0;
}
 
cout/sync
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
 
int n,x;
int main()
{
    freopen("y.in","r",stdin);
    freopen("y.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cout<<i<<endl;
        cout<<-i<<endl;
    }
    return 0;
}
printf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
 
int n,x;
int main()
{
    freopen("y.in","r",stdin);
    freopen("y.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        printf("%d\n%d\n",i,-i);
    }
    return 0;
}
write/template
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
template<typename T>
void write(T w)
{
    if(w<0)putchar('-'),w=-w;
    if(w>9)write(w/10);
    putchar(char(w%10+48));
}
int n,x;
int main()
{
    freopen("y.in","r",stdin);
    freopen("y.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        write(i);
        putchar('\n');
        write(-i);
        putchar('\n');
    }
    return 0;
}
write/int
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
void write(int w)
{
    if(w<0)putchar('-'),w=-w;
    if(w>9)write(w/10);
    putchar(char(w%10+48));
}
int n,x;
int main()
{
    freopen("y.in","r",stdin);
    freopen("y.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        write(i);
        putchar('\n');
        write(-i);
        putchar('\n');
    }
    return 0;
}

结果

方式输入测试1输入测试2输出测试1输出测试2
cin/cout39.1539.2123.9719.31
cin/cout+nosync4.544.4317.7215.13
scanf/printf2.792.836.426.49
read/write(int)0.941.023.133.04
read/write(template)0.980.882.993.07

(注:测试用的pentiumIII处理器(机房配置)大概有点老,我自己i7-7500U的笔记本cin只用6s……不过这样差距更直观了)

可以看出。使用模板的手写读入优化和直接使用int的手写读入优化效率不相上下,scanf要比它们慢3倍左右,取消同步的cin是4.5倍,而直接的cin是40倍!

同样,手写的读入输出优化不相上下。printf为它们的2倍左右,取消同步的cout是5倍左右。但是对于输出,取消同步并没有太大的优势。

小结

可以看出,手写IO优化的效率非常高,而cin/cout的效率非常低。这是一个普遍的规律,兼容性越好的一般效率会比较差。C语言的scanf/printf表现中规中矩。

所以,对于输入输出数据量比较大的题目,使用手写IO优化有时可以起到比较好的效果,一般情况下scanf/printf也足够使用,但是cin/cout在算法竞赛中可能不是那么实用。

打包:一次无聊的实验 密码: 6jv5

0%