C++的常用输入及其优化以及注意事项
$\mathcal{P.S:}$ 对于输入方式及其优化有了解的大佬可直接阅读$\mathcal{Part}$ $\mathcal{2}$
特别鸣谢:@归斋
目录:
$\mathcal{Part}$ $\mathcal{1}$
读入方式们的万年争斗
$\mathcal{Part}$ $\mathcal{2}$
读入不谨慎,爆$\mathcal{0}$两行泪
$\mathcal{Part}$ $\mathcal{1}$ 读入方式们的万年争斗
有一些$\mathcal{OIer}$很喜欢用$\mathcal{cin}$,多方便啊,多好打啊,不像$\mathcal{scanf}$和$\mathcal{printf}$,打那么多%、$\mathcal{""}$、$\mathcal{()}$
这是事实,我在调试程序时用$\mathcal{cin}$和$\mathcal{cout}$也比较多
但是$\mathcal{cin}$和$\mathcal{cout}$也有缺点:
$\mathcal{1}$.格式
比如当你想输出格式$\mathcal{f[a][b]=f[c]+f[d]}$时,用$\mathcal{cout}$就是:
cout<<"f["<<a<<"]["<<b<<"]=f["<<c<<"]+f["<<d<<"]"<<endl;
而用$\mathcal{printf}$的话:
printf("f[%d][%d]=f[%d]+f[%d]",a,b,c,d);
多简洁啊,而且也不易混淆
所以:在输出较为复杂的格式时建议用$\mathcal{printf}$
$\mathcal{2}$.速度
速度可是一个大问题,因为$\mathcal{cin}$和$\mathcal{cout}$的速度可是比$\mathcal{scanf}$和$\mathcal{printf}$慢的
接下来我们测试一下它们的速度:
$\mathcal{1.}$ 输入$\mathcal{10}$万个数字:
两者的差异为$\mathcal{0.031s}$,即$\mathcal{31ms}$.这时$\mathcal{cin}$离$\mathcal{scanf}$就有点远了,那么如果数据更大呢?
$\mathcal{2.}$输入$\mathcal{1000}$万个数字:
$\mathcal{scanf}$的输入速度
$\mathcal{cin}$的输入速度
可以看出两者的差距从$\mathcal{0.031s}$暴涨成$\mathcal{2.58s}$,即$\mathcal{2580ms}$。这个距离就很大啦。
所以说平时做题时,我们一般都用$\mathcal{scanf}$输入而不用$\mathcal{cin}$,因为$\mathcal{cin}$实在太慢啦。
那么$\mathcal{cin}$党是不是就此解散了呢?不不不。首先我们要知道$\mathcal{cin}$为什么这么慢呢?
那是因为$\mathcal{cin}$与$\mathcal{stdin}$有兼容性,也就是说$\mathcal{cin}$与$\mathcal{cin}$总是保持同步,可以放心地混用。
但是这样$\mathcal{cin}$就要背一个$\mathcal{stdin}$啊,当然就比$\mathcal{scanf}$慢咯。所以这是不公平竞争。
为了让$\mathcal{cin}$与$\mathcal{scanf}$公平竞赛,我们当然就应该让$\mathcal{cin}$放下身上的包裹与$\mathcal{scanf}$赛跑。
于是就用到了这句:
ios::sync_with_stdio(false);
这一句的作用是关闭$\mathcal{cin}$与$\mathcal{stdin}$的同步。加上这一句之后$\mathcal{cin}$的速度就可以接近$\mathcal{scanf}$啦
但是,在上面的测试中,$\mathcal{scanf}$竟然不如加了优化的$\mathcal{cin}$!!
这是因为$\mathcal{scanf}$和$\mathcal{cin}$不是那么稳定,毕竟在大多数题中$\mathcal{scanf}$还是比优化后的$\mathcal{cin}$快的
所以这个时候就要手写输入输出啦!
赠送快读快写代码一份~(感谢$\mathcal{}$大佬提供的代码)
inline int read (){//快读
int X = 0,w = 0; char ch = 0;
while(!isdigit(ch)) {w |= ch == '-', ch = getchar();}
while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
return w?-X:X;
}
inline void write (int x){//快写
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
快读的另一个优点就是它可以自动过滤掉多余的字符,这也导致它的缺点就是不能读那种需要读入字符的题...
比如$\mathcal{UVA1292}$一题就可以用快读过滤掉括号,而不用再用$\mathcal{scanf}$过滤了
所以,以后在写读入时,千万不可只写一个$\mathcal{cin}$咯~(至少也得加个优化吧)
$\mathcal{Part}$ $\mathcal{2}$ 读入不谨慎,爆$\mathcal{0}$两行泪
你以为掌握了$\mathcal{Part}$ $\mathcal{1}$你加天下无敌了?$\mathcal{No}$,读入这一块还是有很多坑的~(对于某些大佬来说,的确是天下无敌(比如说@小竹生 @$\mathcal{qingsan}$)...)
$\mathcal{1.}$ 字符读入$\mathcal{--}$讨论$\mathcal{cin}$与$\mathcal{scanf}$
字符的读入对于经验少的$\mathcal{OIer}$来说自古以来都是一个毒瘤之地。
如果你不注意字符读入中的一些坑,那么即使你的算法如何正确,
读入照常把你卡到$\mathcal{0}$分$\mathcal{...}$所以我们首先就来讨论如何处理字符读入的空格吧。
处理方法$\mathcal{1:getchar()+scanf("}$%$\mathcal{c",}$&$\mathcal{x);}$
$\mathcal{getchar}$就是用来吃那该死的空格的和换行的,具体情况具体使用
比如下面这个输入:
5
a a a a a
b b b b b
c c c c c
d d d d d
e e e e e
那么可以用:
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
scanf("%c",&a[i][j]);
getchar();
}
}
这里的$\mathcal{getchar}$就是用来吃掉每一个每一个字符后面的空格的。
但是一旦数据搞事$\mathcal{...}$比如说在每一行后面再加一个空格,那么恭喜你,你的程序把换行给吃进去了
然后就是一调试就是各种神奇的答案...
$\mathcal{getchar}$的缺点就是只吃一个,肚子太小,极易出错。那么怎么办呢?
$\mathcal{2. cin>>...}$ 或 $\mathcal{scanf}$
相信$\mathcal{cin}$是大多数$\mathcal{OIer}$的选择了。
因为用$\mathcal{cin}$读入空格时,遇到空格就会自动停止输入,这样一定程度上就保证了读入时不会读入什么空格换行之类的了。
至于$\mathcal{cin}$的速度,加上那个优化就对了呗。
至于再用$\mathcal{scanf}$?或许你看到这里会觉得很奇怪,刚刚不是才说了$\mathcal{scanf}$会被空格卡吗?
是的,但是对$\mathcal{scanf}$加一点东西它也可以和$\mathcal{cin}$一样对空格免疫:
改进版$\mathcal{scanf}$输入:$\mathcal{scanf("}$ %$\mathcal{c",}$&$\mathcal{x);}$
没错,就是在%$\mathcal{c}$之前加一个空格。这样的$\mathcal{scanf}$和$\mathcal{cin}$一样,对于无论多长的空格和换行都免疫。
2.一种坑有点大的读入 [$\mathcal{SDOI2006}$]保安站岗
读题。嗯,先读入节点编号,再读入当前节点经费,再读入子节点数,再读入对应的子节点。
于是写了这个:
scanf("%d%d%d", &x, &money[x], &m);
for (int i = 1; i <= m; i++) {
scanf("%d", &y);
son[x].push_back(y);
}
然后跑一下样例,发现答案不对,然后又在算法部分查错,死活查不出来,最后生无可恋,砸掉电脑(程序员日常生活$\mathcal{ing}$)。
这种情况最好要检查一下输入啊~输入是基础啊~(╯‵□′)╯︵┻━┻
在每一次读入时都输出$\mathcal{money[x]}$,发现输出都是$\mathcal{money[x]}$那么说明问题就出在$\mathcal{money}$数组的输入。
让我们来想象一个过程:程序把你的这几个输入同时存入,你的第一个数据正在存入$\mathcal{money}$的过程中,你的第二个数据也正在存入$\mathcal{money[x]}$的过程中。第二个数据要存入$\mathcal{money[x]}$,就必须找到对应的$\mathcal{x}$。
按理来说,第一个数据才是第二个数据所对应的$\mathcal{x}$,但是第一个数据还没有存完,第二个数据又必须找到对应的$\mathcal{x}$
于是它只有找上一次的$\mathcal{x}$作为指针,于是就存到上一次的$\mathcal{x}$所对应的值里去了。
不信的话在这个输入后加一个$\mathcal{printf("}$%$\mathcal{d", money[x-1])}$,那么输出肯定就对上输入数据了。
对于这个题来说,实际上可以用
scanf("%d%d%d", &x, &money[i], &m);
但是如果有的题强制你先输入$\mathcal{x}$,再输入$\mathcal{..[x]}$之类的,就没办法啦╮(╯▽╰)╭
$\mathcal{3.}$其他注意事项
有的大佬在有字符读入的题中,喜欢用$\mathcal{scanf}$读入数字,然后用$\mathcal{cin}$读入字符
这样也的确可以,但是有风险!!因为$\mathcal{scanf}$和$\mathcal{cin}$可就没有流同步啦~所以如果混用会有一定的风险。
比如本人在做骑士精神那道题时,就因为混用而出现了玄学$\mathcal{bug}$,成功地爆$\mathcal{0}$了~
-----------------------------------------------------------------------------------------------
总结:输入方面是许多人很少注意的地方,当你检查程序时,个人建议先检查输入输出。(虽然我从来没有这么做过)
如果本文有任何错误或者可以补充的地方,欢迎在下方评论区提出~
C++的常用输入及其优化以及注意事项的更多相关文章
- php面试专题---MySQL常用SQL语句优化
php面试专题---MySQL常用SQL语句优化 一.总结 一句话总结: 原理,万变不离其宗:其实SQL语句优化的过程中,无非就是对mysql的执行计划理解,以及B+树索引的理解,其实只要我们理解执行 ...
- 常用的SQL优化
转自:https://www.cnblogs.com/Cheney222/articles/5876382.html 一.优化 SQL 语句的一般步骤 1 通过 show status 命令了解各种 ...
- PHPSTORM/IntelliJ IDEA 常用 设置配置优化
PHPSTORM/IntelliJ IDEA 常用 设置配置优化 - meetrice 时间 2014-09-06 10:17:00 博客园-所有随笔区 原文 http://www.cnblogs ...
- 项目中常用的MySQL 优化
本文我们来谈谈项目中常用的MySQL优化方法,共19条,具体如下: 一.EXPLAIN 做MySQL优化,我们要善用EXPLAIN查看SQL执行计划. 下面来个简单的示例,标注(1.2.3.4.5)我 ...
- MySQL性能调优与架构设计——第11章 常用存储引擎优化
第11章 常用存储引擎优化 前言: MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.每一种存储引擎都有各自的特长,也都存在一定的短处. ...
- 常用的webpack优化方法
1. 前言 关于webpack,相信现在的前端开发人员一定不会陌生,因为它已经成为前端开发人员必不可少的一项技能,它的官方介绍如下: webpack 是一个模块打包器.webpack的主要目标是将 J ...
- 19条常用的MySQL优化方法(转)
本文我们来谈谈项目中常用的MySQL优化方法,共19条,具体如下:1.EXPLAIN命令做MySQL优化,我们要善用EXPLAIN查看SQL执行计划.下面来个简单的示例,标注(1.2.3.4.5)我们 ...
- PHP常用的一些优化技巧
PHP常用的一些优化技巧 点击联系老杨 ecshop模板 php 优化技巧 老杨ecshop ecshop二次开发 2013-03-29 0 做为最流行的WEB语言, PHP他的突出优势就是其速度与效 ...
- 6-JVM常用工具和优化
JVM 常用工具和优化 JDK 自带的 jconsole jvisualvm 三方的工具 arthas 调优关注点(内存.GC): 内存 MAT XElephant 在线:perfma GC 拿到GC ...
随机推荐
- Ticket Game思维题
题目链接 题意: 给你一个n的序列(n=2*k),由数字和?(偶数个)组成,A和B分别操作(B先操作):把?变成一个任意的0-9的数字,如果最后前n/2和后n/2个数字之和相等,则A胜,否则B胜. 分 ...
- Django---进阶3
目录 无名有名分组反向解析 路由分发 名称空间(了解) 伪静态(了解) 虚拟环境(了解) django版本区别 视图层 三板斧 JsonResponse对象 form表单上传文件及后端如何操作 req ...
- SaaS 系统架构,Spring Boot 动态数据源实现!
这段时候在准备从零开始做一套SaaS系统,之前的经验都是开发单数据库系统并没有接触过SaaS系统,所以接到这个任务的时候也有也些头疼,不过办法部比困难多,难得的机会. 在网上找了很多关于SaaS的资料 ...
- Linux多任务编程之二:fork()函数及其基础实验(转)
来源:CSDN 作者:王文松 转自Linux公社 fork()函数 在 Linux 中创建一个新进程的唯一方法是使用fork()函数.fork()函数是 Linux 系统中一个非常重要的函数,和咱们 ...
- 数据可视化之DAX篇(五) 使用PowerBI的这两个函数,灵活计算各种占比
https://zhuanlan.zhihu.com/p/57861350 计算个体占总体的比例是一个很常见的分析方式,它很简单,就是两个数字相除,但是当需要计算的维度.总体的范围发生动态变化时,如何 ...
- DEX文件解析--5、dex方法原型解析
一.前言 前几篇文章链接: DEX文件解析---1.dex文件头解析 DEX文件解析---2.Dex文件checksum(校验和)解析 DEX文件解析--3.dex文件字 ...
- 2019CSP-J T4 加工零件
题目描述 凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇.工厂里有 n 位工人,工人们从 1 ∼n 编号.某些工人之间存在双向的零件传送带.保证每两名工人之间最多只存在一 ...
- 【Docker】Redis 安装使用教程
1.安装 1.1 拉取镜像 docker pull redis redis:4.0 1.2 创建redis容器名"redistest1",并开启持久化 docker run -d ...
- 设计模式:interpreter模式
理解:可以广义的理解为创造一种语言,实现该语言的解释器,然后用创造的语言编写程序 对比:如xml就是一种语言,解析xml的代码就是解释器 例子: //目标:定义4中几种命令,使用C++解析 //如下: ...
- DP学习记录Ⅰ
DP学习记录Ⅱ 前言 状态定义,转移方程,边界处理,这三部分想好了,就问题不大了.重点在状态定义,转移方程是基于状态定义的,边界处理是方便转移方程的开始的.因此最好先在纸上写出自己状态的意义,越详细越 ...