IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 快读快写(以及一些其他神奇技巧)の小攻略 -> 正文阅读

[C++知识库]快读快写(以及一些其他神奇技巧)の小攻略

作为一个专业 fake快读/快写/压行/宏定义/类/人,今天就来给大家讲一些有趣的小技巧
因为太菜了所以大家多多包涵
因为太菜了,所以像ahy、dms这样的大佬就看个笑话就行了呜呜呜

快读&快写

在数据量超过1e6的时候,快读快的不是一星半点——笔者自己说的

快读

众所周知,常用的读入方式有三种:
1.cin
2.scanf
3.getchar

没错,你现在一定很懵:什么?说好的快速读入呢?
别着急,听我细细道来
首先呢我们回忆回忆呗,当你刚接触oi的时候,你觉得最好用的读入是什么呢
我觉得大多数人都会觉得cin很好用吧,写起来简单,不需要考虑格式化输入都是cin的优点
但是在教练的强制禁令之下,你停止了使用cin,改用scanf了,但是你不知道为什么
你可能只觉得:WA!scanf好麻烦啊,内个什么文本替代我根本记不住啊,还不如cin呢,也许有人偶尔还在偷偷用着cin
直到有一天,你做着一道数据稍稍大了一点点的题,你觉得没什么问题,你提交了,然后就是
TLE
但是你并不知道为什么,但是当你重构的时候一不小心写成了scanf或者是看题解写了scanf你就借鉴了,总之你惊奇地发现cin读入速度竟然慢于scanf,于是为了AC,你就走上了坚定不移的scanf之路,但是走着走着,数据来到了1e6以上,你发现有的时候scanf都满足不了你了,甚至有时还有奇怪的输入,scanf不好用了!
你迫切地需要一款更快的读入!
于是我们今天的主要话题应运而生:
如何加快读入
在进入正式介绍快读之前,首先有个小彩蛋,就是cin是可以优化的,你只要加上这句:

ios::sync_with_stdio(false);

cin,cout之所以效率低,是因为先把要输出的东西存入缓冲区,再输出,导致效率降低,而这段语句可以来打消iostream的输入输出缓存,可以节省许多时间,使效率与scanf与printf相差无几,但是还是比scanf与printf略慢,但已经不影响题目通过了。
这个函数是一个“是否兼容stdio”的开关,C++为了兼容C,保证程序在使用了std::printf和std::cout的时候不发生混乱,将输出流绑到了一起。
所以使用ios::sync_with_stdio(false);后就不能把cin、cout和scanf、printf混用了,否则有一定几率会发生输入输出和预想不一样的情况。
所以还是不要用cin、cout了
那么现在我们来介绍一个更快的读入方式吧
当遇到相当大的数据的时候(一般1e6以上),或者我们用其他方式卡常已经不能再快了,这时我们可以使用快读
快读原理是什么呢?
显然,读入字符可比读入数字快多了,那么我们就按字符挨个读入,读入后用ASCII码处理成数字,这样就很快了
最基本的快读就像这样↓

inline int read(){
    int x=0,f=1;char c=getchar();
    //这里isdigit()也可以改为通过ASCII判断,如何判断很大程度上取决于你是否使用万能头
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}

不过快读也有可能被卡,比如一个数据有很多很多空格
笔者还没有见过如此毒瘤的数据(
你觉得这就完了吗?
而实际上,甚至还有更快的读入方式:fread
这个函数的原理就是先把数据流中的一整段都存下来,然后从这个数组里读取,直到数组读空了再重新从数据流中读取,由于是整段整段读取,所以自然比getchar()要快的多。
这两个东西在各种OJ上面还是适用的,因为OJ上就是文件读入输出的。
不过我们会发现,一旦用了这个读入优化。getchar,scanf都不能用了(存到buf里了),所有读入都必须自己写了。所以说数据流不是太大的时候(如1*10^6),可以考虑不用这个读入优化。
代码长这样↓

static char buf[1000000],*p1=buf,*p2=buf,obuf[1000000],*p3=obuf;
#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++
inline int read(){
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}

四种读入方式分别的时间
测试用题为st表模板
基本忽略因评测机原因的上下浮动
控制单一变量为读入方式
自下而上为cin(甚至T了,垃圾)→scanf→读入优化→fread读入优化
在这里插入图片描述
四种方式各有优缺点,下面我们就来总结一下

非常方便方便多种读入类型能过非常快终端调试
cin×
scanf
读入优化
fread×

最后就是笔者在使用不同读入时总结的一些问题、经验和教训
cin:没什么可说的,因为太垃圾笔者没用过
scanf:
1.使用scanf的时候最容易犯的也是最常见的问题就是没打取地址符,这个问题是不会CE,只会RE,但是一定要注意!scanf输入字符串本来也没有取地址符!
2.少一个或者多一个%d也是很常见的问题,多一个%d会因为找不到地址RE,少一个%d你的变量就会少值
3.文本替代符写错类型也是一个常见问题,尤其是%lld和%d,一定要确定好读入类型再写文本替代符
读入优化:
1.读入优化最最最最最容易出现的问题就是类型,虽然只能是int或者ll,但是一定要看好读入的的变量将会是什么类型,这里千万不能写错,ll写成int你题就炸了,int写成ll可能连赋值都做不到
2.只能用于整数,如果有什么浮点数建议直接放弃
3.写的时候一定要注意好别写错了,比如少个getchar之类的,如果没了会直接TLE或者RE
fread:
1.同读入优化
2.只能使用文件读入

快写

内容基本与快读一致,此处将给出代码但不予赘述,请读者自行理解
快速读入唯一的问题是不能输出0,这里需要自行特判
以及fwrite可以在终端输入的情况下使用,但是会直接输出为文件形式
原初の快速输出↓

inline void write(int x){ 
    if(x==0){putchar('0');return;}
	int len=0,k1=x,c[10005];
	if(k1<0)k1=-k1,putchar('-');
	while(k1)c[len++]=k1%10+'0',k1/=10;
	while(len--)putchar(c[len]);
}

fwrite快速输出↓

static char buf[1000000],*p1=buf,*p2=buf,obuf[1000000],*p3=obuf;
#define putchar(x) (p3-obuf<1000000)?(*p3++=x):(fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=x)
inline void write(int x){ 
    if(x==0){putchar('0');return;}
	int len=0,k1=x,c[10005];
	if(k1<0)k1=-k1,putchar('-');
	while(k1)c[len++]=k1%10+'0',k1/=10;
	while(len--)putchar(c[len]);
}

那么我们有关快读快写的一些主要内容就结束了,下面是

一些私货神奇技巧

关于高亮

笔者个人比较喜欢对比度较高的,颜色比较鲜亮的高亮主题,比如Matrix、Just Black,有的时候一个对比度高的高亮也许能救你一命!

关于压行

笔者觉得将代码压行是一种艺术,紧凑的代码风格简直是美极了,将同一功能的句落压到一行有助于debug,没有必要展开的if和for就写到一行就完了,比如笔者本人曾经将树剖板子写到了优美的90行

关于宏定义

相较于typedef和const int,笔者比较喜欢整齐划一的define,不但方便写一些冗长的语句,而且宏定义有的时候能有效地减少变量的数量,降低程序的空间常数

关于类

类是非常有用的东西,毕竟是C++三大特性之一,你可以利用类轻松地将一些很冗长的和数据结构有关的或者实现某种指定功能的代码(比如树剖)封装到一个类里面,然后你就可以轻松的像使用STL一样使用它了,笔者很喜欢将什么线段树st表并查集图树矩阵之类的东西存到类里

这基本上就是全部内容了,不喜勿喷,欢迎补充

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-10 10:40:43  更:2021-09-10 10:40:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 12:46:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计