丢人笔记:黑科技——使用streambuf加速读入输出

UPD20191125:我发现我又丢人了,sgetc只会读取缓冲区当前字符而不会前移读取位置,想要读取并前移读取位置应该用sbumpc。。。

  一般情况下,在C++中,iostream内的cin和cout是比scanf和printf慢的,这主要是为了同时兼容iostream和stdio,iostream与stdio的缓冲区被绑到了一起,以及cin和cout的stream是绑定在一起的,这使得cin和cout有额外的开销

  为了提高cin和cout的效率,我们可以取消iostream与stdio的同步,以及cin和cout的stream的绑定:

1 std::ios::sync_with_stdio(false);
2 cin.tie(NULL);
3 cout.tie(NULL);

  这样cin与cout就比scanf和printf快了。在本机测试上,iostream甚至比stdio快了6倍左右。然而这样做之后,就不可以将iostream与stdio混用了,然而输入量较大的时候,这种方法仍然无能为力

  在stdin中,我们有getchar,想要追求更快的速度,我们有fread

  在iostream中我们同样可以达到同样的效率,甚至更快:

  首先要获取cin的streambuf:

std::streambuf *fb = cin.rdbuf();

  然后我们就可以进行类似stdio中的操作:

  对于getchar,我们有sbumpc,它的用法等同于getchar,速度略快于getchar:

char ch = fb -> sbumpc();

  对于fread,我们有sgetn,它的用法与fread类似,速度略快于fread:

#define MAX_INPUT 1000000
char buf[MAX_INPUT]
int main() {
    fb -> sgetn(buf, MAX_INPUT);
    return 0;
}

  输入问题就解决了。还有输出问题:

  (不知道为什么,网上的输出代码在我这边不会进行输出,然而我这边手写的输出比fwrite慢了好多。。。。)

  对于putchar,我们有sputc,它的用法等同于putchar,速度略快于putchar:

char ch = '\n';
fb -> sputc(ch);

  对于fwrite,我们有sputn,它的用法与fwrite类似,速度略快于fwrite?

#define MAX_OUTPUT 1000000
char buf[MAX_OUTPUT];
int main() {
    fb -> sputn(buf, MAX_OUTPUT);
    return 0;
}

  这样我们就有了一份完整的快速输入输出 丢人 代码(因为sputn的那份比sputc还慢,所以这里就用了sputc的代码):

#include<iostream>
#include<cctype>
using std::cin;
using std::cout;
using std::endl;
namespace IN {
    #define MAX_INPUT 1000000
    #define cinchar() ((fs == ft && (ft = (fs = buf) + fb -> sgetn(buf, MAX_INPUT))) ? 0 : *fs++)
    char buf[MAX_INPUT], *fs, *ft;
    inline int read() {
        static std::streambuf *fb = cin.rdbuf();
        register int x = 0;
        register bool f = false;
        register char ch = cinchar();
        while (!isdigit(ch)) {
            if (ch == '-') f = true;
        ch = cinchar();
        }
        while (isdigit(ch)) {
            x = (x << 1) + (x << 3) + ch - '0';
            ch = cinchar();
        }
        return f ? -x : x ;
    }
    #undef MAX_INPUT
    #undef cinchar
}

namespace OUT {
    inline void put(int x) {
        static std::streambuf *fb = cout.rdbuf();
        static char stack[11];
        static int top = 0;
        if (!x) {
            fb -> sputc('0');
            fb -> sputc('\n');
            return;
        }
        while (x) {
            stack[++top] = x % 10 + '0';
            x /= 10;
        }
        while (top) {
            fb -> sputc(stack[top]);
            --top;
        }
        fb -> sputc('\n');
    }
}

int main() {
    freopen("add.in", "r", stdin);
    std::ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int a = IN::read(), b = IN::read();
    OUT::put(a + b);
    return 0;
}

 为了丢人,在这里贴上sputn的代码

 1 namespace OUT {
 2     #define MAX_OUTPUT 1000000
 3     char buf[MAX_OUTPUT], *fs = buf, *ft = buf + MAX_OUTPUT;
 4     #define coutchar(ch) *fs++ = ch
 5     inline void put(int x) {
 6         static std::streambuf *fb = cout.rdbuf();
 7         static char stack[11];
 8         static int top = 0;
 9         if (!x) {
10             coutchar('0'); coutchar('\n');
11             return;
12         }
13         while (x) {
14             stack[++top] = x % 10 + '0';
15             x /= 10;
16         }
17         while (top) {
18             *fs++ = stack[top];
19             --top;
20         }
21         coutchar('\n');
22         fb -> sputn(buf, fs - buf);
23         fs = buf;
24     }
25     #undef coutchar
26     #undef MAX_OUTPUT
27 }
sputn

代码部分参考自:https://blog.csdn.net/simpsonk/article/details/78457842

 

至于对标 printf 的格式化输出,不如等算法竞赛兼容 std::format 吧(乐)

posted @ 2018-04-14 08:46  hinanawi  阅读(2745)  评论(0编辑  收藏  举报