查看: 1078|回复: 2

[C/C++] C++读入优化

[复制链接]

1

技术

25

魅力

7

原创

管理员

Rank: 9Rank: 9Rank: 9

积分
11343
人气
297
分享
42

论坛元老优秀版主活跃会员最佳新人灌水之王

发表于 2021-10-4 17:04:44 | 显示全部楼层 |阅读模式
在介绍读入优化之前,我们先编写程序,读入1万个随机整数,对比一下cin和scanf读取所花的时间
scanf
13ms
cin
44ms
大家有没有发现,scanf比cin快了好几倍?

接下来,我们输入20万个随机整数,测得的时间如下:
scanf
396ms
cin
1214ms
在很多竞赛中,代码运行时间限制为1秒,也就是说用cin读取20万个整数已经超时了,scanf读取也非常慢,那如何加快读取的速度呢?

首先介绍一个函数getchar,getchar可以读入一个字符(char),而且速度非常快,我们可以用来编写读入优化函数,代码如下:
[C++] 纯文本查看 复制代码
void read(int& x)
{
        int f = 1; // 初始化
        x = 0; 
        char s = getchar(); // 读入一个字符
        while (s < '0' || s > '9') { // 如果这个字符不是数字,则进入循环
                if (s == '-') // 判断该字符是否为负号,注意,不能直接将f的值设为-1
                        f = -1; // 将该整数标记为负数
                s = getchar(); // 继续读入字符
        }
        while (s >= '0' && s <= '9') { // 如果这个字符是数字,则进入循环
                x = x * 10 + s - '0'; // 在x后面添0,然后加上读入的数字
                s = getchar(); // 继续读入字符
        }
        x *= f; // 改变正负
}

经测试,该函数读取20万个随机整数的时间为225ms,已经比scanf速度快了很多。

我在网上搜索之后,发现还有一种更快的读入优化方法,使用fread函数读入:
[C++] 纯文本查看 复制代码
inline char nc() {
        static char buf[1000000], * p1 = buf, * p2 = buf;
        return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
void read(int& x)
{
        int f = 1; // 初始化
        x = 0; 
        char s = nc(); // 读入一个字符
        while (s < '0' || s > '9') { // 如果这个字符不是数字,则进入循环
                if (s == '-') // 判断该字符是否为负号,注意,不能直接将f的值设为-1
                        f = -1; // 将该整数标记为负数
                s = nc(); // 继续读入字符
        }
        while (s >= '0' && s <= '9') { // 如果这个字符是数字,则进入循环
                x = x * 10 + s - '0'; // 在x后面添0,然后加上读入的数字
                s = nc(); // 继续读入字符
        }
        x *= f; // 改变正负
}

这里的nc相当于上文的getchar函数。

我们使用这种方法读入20万个随机整数,竟然达到了惊人的60ms!!!


Just do it.

0

技术

0

魅力

2

原创

初出茅庐

Rank: 2

积分
296
人气
13
分享
1
发表于 2021-10-4 18:03:27 | 显示全部楼层
好慢啊。
建议
[C++] 纯文本查看 复制代码
#include <cstdio>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

using namespace std;

#define MAXN 11111111

#define Finline __inline__ __attribute__ ((always_inline))

char *pc;

inline int read(){
    int num = 0;
    char c;
    while ((c = *pc++) < 48);
    while (num = num * 10 + c - 48, (c = *pc++) >= 48);
    return num;
}

inline int test(){
    pc = (char *) mmap(NULL, lseek(0, 0, SEEK_END), PROT_READ, MAP_PRIVATE, 0, 0);
    int recieve_int, ret = 0;
    for(int i = 0; i < MAXN; i++){
        recieve_int = read();
        ret += recieve_int;
    }
    char recieve_char;
    while((recieve_char = *pc++) < 60);
    ret -= recieve_char;
    for(int i = 0; i < MAXN; i++){
        recieve_char = *pc++;
        ret -= recieve_char;
    }
    return ret + 1;
}

int main(){
    freopen("fr.in", "r", stdin);
    printf("%d", test());
    fclose(stdin);
    return 0;
}


0

技术

0

魅力

2

原创

初出茅庐

Rank: 2

积分
296
人气
13
分享
1
发表于 2021-10-4 18:11:41 | 显示全部楼层
另外道一下,关闭同步和tie的cin相当于fread了,大部分使用得当情况下比scanf快
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表