跳转至

输入输出优化

在默认情况下,std::cin/std::cout 是极为迟缓的读入/输出方式,而 scanf/printf 比 std::cin/std::cout 快得多。


Cpp优化:关闭同步、解除绑定

std::ios::sync_with_stdio(false);

这个函数是一个「是否兼容 stdio」的开关,C++ 为了兼容 C,保证程序在使用了 printf 和 std::cout 的时候不发生混乱,将输出流绑到了一起。同步的输出流是线程安全的。

这其实是 C++ 为了兼容而采取的保守措施,也是使 cin/cout 速度较慢的主要原因。我们可以在进行 IO 操作之前将 stdio 解除绑定,但是在这样做之后要注意:不能同时使用 std::cin 和 scanf,也不能同时使用 std::cout 和 printf;可以同时使用 std::cin 和 printf,也可以同时使用 scanf 和 std::cout

tie

tie 是将两个 stream 绑定的函数,空参数的话返回当前的输出流指针。

在默认的情况下 std::cin.tie() 绑定的是 &std::cout,每次进行格式化输入的时候都要调用 std::cout.flush() 清空输出缓冲区,这样会增加 IO 负担。可以通过 std::cin.tie(nullptr) 来解除绑定,进一步加快执行效率。

但需要注意的是,在解除了 std::cin 和 std::cout 的绑定后,程序中必须手动 flush 才能确保每次 std::cout 展现的内容可以在 std::cin 前出现。这是因为 std::cout 被 buffer 为默认设置。例如:

1
2
3
4
cout << "Please input your name: " << std::flush; 
// 或者: std::endl; 因为每次调用 std::endl 都会 flush 输出缓冲区,而 \n 则不会。
// 谨慎使用,过多的 flush 会影响程序效率
cin >> name;

实现

ios::sync_with_stdio(false);
cin.tie(nullptr);

C优化:getchar/putchar

输入

int read() { 
    int x = 0, w = 1; 
    char ch = 0; 
    while (ch < '0' || ch > '9') {  // ch 不是数字时 
        if (ch == '-') w = -1;      // 判断是否为负 
        ch = getchar();             // 继续读入 
    } 
    while (ch >= '0' && ch <= '9') {  // ch 是数字时 
        x = x * 10 + (ch - '0');      // 将新读入的数字「加」在 x 的后面 
        // x 是 int 类型,char 类型的 ch 和 '0' 会被自动转为
        // 对应 ASCII 码,相当于将 ch 转化为对应数字 
        // 此处也可以用 (x<<3)+(x<<1) 代替 x*10 
        ch = getchar();               // 继续读入 
    } 
    return x * w;  // 数字 * 正负号 = 实际数值 
}

读入 num 写为 num=read();

输出

1
2
3
4
5
6
7
8
void write(int x) {
  if (x < 0) {  // 判负 + 输出负号 + 变原数为正数
    x = -x;
    putchar('-');
  }
  if (x > 9) write(x / 10);  // 递归,将除最后一位外的其他部分放到递归中输出
  putchar(x % 10 + '0');     // 已经输出(递归)完 x 末位前的所有数字,输出末位
}

但是递归实现常数是较大的,我们可以写一个栈来实现这个过程。

1
2
3
4
5
6
7
8
void write(int x) {
  static int sta[35];
  int top = 0;
  do {
    sta[top++] = x % 10, x /= 10;
  } while (x);
  while (top) putchar(sta[--top] + 48);  // 48 是 '0'
}

输出 num 写为 write(num);

参考

读入、输出优化 - OI Wiki