Loading docs/misc/io.md +41 −54 Original line number Diff line number Diff line Loading @@ -74,11 +74,11 @@ int read(){ ### 原理 同样是众所周知,`putchar` 是输出单个字符,其速度远快于其它输出方式 同样是众所周知,`putchar` 是输出单个字符 因此将数字的每一位转化为字符输出以加速 要注意的是,负号要单独判断输出,并且每次 %(mod)取出的是数字末位,因此要倒序输出(递归加速) 要注意的是,负号要单独判断输出,并且每次 %(mod)取出的是数字末位,因此要倒序输出 ### 代码实现 Loading @@ -99,85 +99,72 @@ int write(int x){ } ``` 但是递归实现是很慢的,我们可以写一个栈来实现这个过程 ```cpp inline 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);` 也可以写成非递归的形式,来得到更好的效果。 ## 更快的读入 / 输出优化 通过 `fread` 或者 `mmap` 可以实现更快的读入和输出。其本质为一次性读入 / 输出一个巨大的缓存区,如此比一个一个字符读入输出要快的多 (`getchar`,`putchar`)。 通过 `fread` 或者 `mmap` 可以实现更快的读入。其本质为一次性读入一个巨大的缓存区,如此比一个一个字符读入要快的多 (`getchar`,`putchar`)。 因为硬盘的多次读写速度是要慢于内存的,先一次性读到内存里在读入要快的多。 更通用的是 `fread`,因为 `mmap` 不能在 Windows 使用。 `fread`类似于`scanf("%s")`,不过它更为快速,而且可以一次性读入若干个字符(包括空格换行等制表符),如果缓存区足够大,甚至可以一次性读入整个文件。 对于输出,我们还有对应的 `fwrite` 函数 ```cpp std::size_t fread( void* buffer, std::size_t size, std::size_t count, std::FILE* stream ); std::size_t fwrite( const void* buffer, std::size_t size, std::size_t count, std::FILE* stream ); ``` 使用示例:`fread(Buf, 1, MAXSIZE, stdin)`,如此从 stdin 文件流中读入 MAXSIZE 个字符到 Buf 中。 使用示例:`fread(Buf, 1, MAXSIZE, stdin)`,如此从 stdin 文件流中读入 MAXSIZE 个大小为 1 的字符到 Buf 中。 读入之后的使用就跟普通的读入优化相似了,只需要重定义一下 getchar。它原来是从文件中读入一个 char,现在变成从 Buf 中读入一个 char,也就是头指针向后移动一位。 ```cpp char Buf[MASIZE], *S = Buf; char getchar() { return *S++; } char buf[1<<20], *p1, *p2; #define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++) ``` `fwrite` 也是类似的,先放入一个 `OutBuf[MAXSIZE]` 中,最后通过 `fwrite` 一次性将 `OutBuf` 输出。 注意 `fread` 必须使用文件读入,但是 `fwrite` 不需要。 参考代码: ```text namespace io { const int MAXSIZE = 1 << 22; inline char gc() { static char In[MAXSIZE], *at = In, *en = In; if (at == en) { en = (at = In) + fread(In, 1, MAXSIZE, stdin); } return at == en ? EOF : *at++; } template <class T> inline T gt() { char c; while (c = gc(), !isdigit(c) && c != '-') {} bool f = c == '-'; T x = f ? 0 : c - '0'; for (c = gc(); isdigit(c); c = gc()) { x = x * 10 + c - '0'; } return f ? -x : x; } char Out[MAXSIZE], *cur = Out, *end = Out + MAXSIZE - 100; void flush() { fwrite(Out, 1, cur - Out, stdout); cur = Out; } template <typename T> inline void pt(T x, char c = '\n') { static int S[20], *top; top = S; if (x < 0) { *cur++ = '-', x = -x; ```cpp namespace IO { const int MAXSIZE = 1 << 20; char buf[MAXSIZE], *p1, *p2; #define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin),p1==p2)?EOF:*p1++) inline int rd() { int x = 0, f = 1;char c=nc(); while(!isdigit(c)) {if(c == '-') f = -1; c = nc();} while(isdigit(c)) x = (x<<1)+(x<<3)+(c^48), c = nc(); return x*f; } do { *++top = x % 10, x /= 10; } while (x); while (top != S) { *cur++ = *top-- + '0'; char pbuf[1<<20],*pp=pbuf; inline void push(const char &c) { if(pp-pbuf==1<<20) fwrite(pbuf,1,1<<20,stdout),pp=pbuf; *pp++=c; } *cur++ = c; if(cur >= end) { flush(); inline void write(int x) { static int sta[35]; int top=0; do{sta[top++]=x%10,x/=10;}while(x); while(top) push(sta[--top]+'0'); } } } // namespace io ``` ## 参考 Loading Loading
docs/misc/io.md +41 −54 Original line number Diff line number Diff line Loading @@ -74,11 +74,11 @@ int read(){ ### 原理 同样是众所周知,`putchar` 是输出单个字符,其速度远快于其它输出方式 同样是众所周知,`putchar` 是输出单个字符 因此将数字的每一位转化为字符输出以加速 要注意的是,负号要单独判断输出,并且每次 %(mod)取出的是数字末位,因此要倒序输出(递归加速) 要注意的是,负号要单独判断输出,并且每次 %(mod)取出的是数字末位,因此要倒序输出 ### 代码实现 Loading @@ -99,85 +99,72 @@ int write(int x){ } ``` 但是递归实现是很慢的,我们可以写一个栈来实现这个过程 ```cpp inline 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);` 也可以写成非递归的形式,来得到更好的效果。 ## 更快的读入 / 输出优化 通过 `fread` 或者 `mmap` 可以实现更快的读入和输出。其本质为一次性读入 / 输出一个巨大的缓存区,如此比一个一个字符读入输出要快的多 (`getchar`,`putchar`)。 通过 `fread` 或者 `mmap` 可以实现更快的读入。其本质为一次性读入一个巨大的缓存区,如此比一个一个字符读入要快的多 (`getchar`,`putchar`)。 因为硬盘的多次读写速度是要慢于内存的,先一次性读到内存里在读入要快的多。 更通用的是 `fread`,因为 `mmap` 不能在 Windows 使用。 `fread`类似于`scanf("%s")`,不过它更为快速,而且可以一次性读入若干个字符(包括空格换行等制表符),如果缓存区足够大,甚至可以一次性读入整个文件。 对于输出,我们还有对应的 `fwrite` 函数 ```cpp std::size_t fread( void* buffer, std::size_t size, std::size_t count, std::FILE* stream ); std::size_t fwrite( const void* buffer, std::size_t size, std::size_t count, std::FILE* stream ); ``` 使用示例:`fread(Buf, 1, MAXSIZE, stdin)`,如此从 stdin 文件流中读入 MAXSIZE 个字符到 Buf 中。 使用示例:`fread(Buf, 1, MAXSIZE, stdin)`,如此从 stdin 文件流中读入 MAXSIZE 个大小为 1 的字符到 Buf 中。 读入之后的使用就跟普通的读入优化相似了,只需要重定义一下 getchar。它原来是从文件中读入一个 char,现在变成从 Buf 中读入一个 char,也就是头指针向后移动一位。 ```cpp char Buf[MASIZE], *S = Buf; char getchar() { return *S++; } char buf[1<<20], *p1, *p2; #define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++) ``` `fwrite` 也是类似的,先放入一个 `OutBuf[MAXSIZE]` 中,最后通过 `fwrite` 一次性将 `OutBuf` 输出。 注意 `fread` 必须使用文件读入,但是 `fwrite` 不需要。 参考代码: ```text namespace io { const int MAXSIZE = 1 << 22; inline char gc() { static char In[MAXSIZE], *at = In, *en = In; if (at == en) { en = (at = In) + fread(In, 1, MAXSIZE, stdin); } return at == en ? EOF : *at++; } template <class T> inline T gt() { char c; while (c = gc(), !isdigit(c) && c != '-') {} bool f = c == '-'; T x = f ? 0 : c - '0'; for (c = gc(); isdigit(c); c = gc()) { x = x * 10 + c - '0'; } return f ? -x : x; } char Out[MAXSIZE], *cur = Out, *end = Out + MAXSIZE - 100; void flush() { fwrite(Out, 1, cur - Out, stdout); cur = Out; } template <typename T> inline void pt(T x, char c = '\n') { static int S[20], *top; top = S; if (x < 0) { *cur++ = '-', x = -x; ```cpp namespace IO { const int MAXSIZE = 1 << 20; char buf[MAXSIZE], *p1, *p2; #define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin),p1==p2)?EOF:*p1++) inline int rd() { int x = 0, f = 1;char c=nc(); while(!isdigit(c)) {if(c == '-') f = -1; c = nc();} while(isdigit(c)) x = (x<<1)+(x<<3)+(c^48), c = nc(); return x*f; } do { *++top = x % 10, x /= 10; } while (x); while (top != S) { *cur++ = *top-- + '0'; char pbuf[1<<20],*pp=pbuf; inline void push(const char &c) { if(pp-pbuf==1<<20) fwrite(pbuf,1,1<<20,stdout),pp=pbuf; *pp++=c; } *cur++ = c; if(cur >= end) { flush(); inline void write(int x) { static int sta[35]; int top=0; do{sta[top++]=x%10,x/=10;}while(x); while(top) push(sta[--top]+'0'); } } } // namespace io ``` ## 参考 Loading