C++的常用输入及其优化以及注意事项

$P.S:$ 对于输入方式及其优化有了解的大佬可直接阅读$Part$ $2$

特别鸣谢:@归斋
目录:

$Part$ $1$
                                                       读入方式们的万年争斗

$Part$ $2$
                                                       读入不谨慎,爆0两行泪

$Part$ $1$ 读入方式们的万年争斗

有一些$OIer$很喜欢用$cin$,多方便啊,多好打啊,不像$scanf$和$printf$,打那么多%、$""$、$()$

这是事实,我在调试程序时用$cin$和$cout$也比较多

但是$cin$和$cout$也有缺点:

1.格式

比如当你想输出格式$f[a][b]=f[c]+f[d]$时,用$cout$就是:

cout<<"f["<<a<<"]["<<b<<"]=f["<<c<<"]+f["<<d<<"]"<<endl;

而用$printf$的话:

printf("f[%d][%d]=f[%d]+f[%d]",a,b,c,d);

多简洁啊,而且也不易混淆

所以:在输出较为复杂的格式时建议用$printf$

2.速度

速度可是一个大问题,因为$cin$和$cout$的速度可是比$scanf$和$printf$慢的

接下来我们测试一下它们的速度:

$1.$ 输入$10$万个数字:

![cin输入速度.png](https://i.loli.net/2019/08/17/IcGLpMCuJqPjySV.png)

![scanf输入速度.png](https://i.loli.net/2019/08/17/FBKo7jpXPHk2s4v.png)

两者的差异为$0.031s$,即$31ms$.这时$cin$离$scanf$就有点远了,那么如果数据更大呢?

$2.$输入$1000$万个数字:

![scanf输入速度2.png](https://i.loli.net/2019/08/17/JOMS43CLwKiPVnp.png)

($scanf$的速度)

![cin输入速度2.png](https://i.loli.net/2019/08/17/woaRM637VQ15US4.png)

($cin$的速度)

可以看出两者的差距从$31ms$暴涨成$2.58s$,即$2580ms$。这个距离就很大啦。

所以说平时做题时,我们一般都用$scanf$输入而不用$cin$,因为$cin$实在太慢啦。

那么$cin$党是不是就此解散了呢?不不不。首先我们要知道$cin$为什么这么慢呢?

那是因为$cin$与$stdin$有兼容性,也就是说$cin$与$stdin$总是保持同步,可以放心地混用。

但是这样$cin$就要背一个$stdin$啊,当然就比$scanf$慢咯。所以这是不公平竞争。

为了让$cin$与$scanf$公平竞赛,我们当然就应该让$cin$放下身上的包裹与$scanf$赛跑。

于是就用到了这句:

```cpp
ios::sync_with_stdio(false);
```

这一句的作用是关闭$cin$与$stdin$的同步。加上这一句之后$cin$的速度就可以接近$scanf$啦

但是,在上面的测试中,$scanf$竟然不如加了优化的$cin$!!

这是因为$scanf$和$cin$不是那么稳定,毕竟在大多数题中$scanf$还是比优化后的$cin$快的

所以这个时候就要手写输入输出啦!

赠送快读快写代码一份~(感谢[email protected]$大佬提供的代码)
```cpp
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‘);
}
```

快读的另一个优点就是它可以自动过滤掉多余的字符,这也导致它的缺点就是不能读那种需要读入字符的题...

比如[UVA1292](https://www.luogu.org/problem/UVA1292)一题就可以用快读过滤掉括号,而不用再用$scanf$过滤了

所以,以后在写读入时,千万不可只写一个$cin$咯~(至少也得加个优化吧)

## $Part$ $2$ 读入不谨慎,爆0两行泪

你以为掌握了$Part$ $1$你加天下无敌了?$No$,读入这一块还是有很多坑的~(对于某些大佬来说,的确是天下无敌(比如说@小竹生 @$qingsan$)...)

$1.$ 字符读入$--$讨论$cin$与$scanf$

字符的读入对于经验少的$OIer$来说自古以来都是一个毒瘤之地。

如果你不注意字符读入中的一些坑,那么即使你的算法如何正确,
读入照常把你卡到$0$分$...$所以我们首先就来讨论如何处理字符读入的空格吧。

处理方法$1:getchar()+scanf("$%$c", $&$x);$

$getchar$就是用来吃那该死的空格的和换行的,具体情况具体使用
比如下面这个输入:
```cpp
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
```

那么可以用:
```cpp
for(int i=1; i<=n; i++) {
     for(int j=1; j<=n; j++) {
          scanf("%c",&a[i][j]);
          getchar();
     }
}
```

这里的$getchar$就是用来吃掉每一个每一个字符后面的空格的。

但是一旦数据搞事$...$比如说在每一行后面再加一个空格,那么恭喜你,你的程序把换行给吃进去了

然后就是一调试就是&^%$#@!

$getchar$的缺点就是只吃一个,肚子太小,极易出错。那么怎么办呢?

$2. cin>>...$ 或 $scanf$

相信$cin$是大多数$OIer$的选择了。

因为用$cin$读入空格时,遇到空格就会自动停止输入,这样一定程度上就保证了读入时不会读入什么空格换行之类的了。

至于$cin$的速度,加上那个优化就对了呗。

至于再用$scanf$?或许你看到这里会觉得很奇怪,刚刚不是才说了$scanf$会被空格卡吗?

是的,但是对$scanf$加一点东西它也可以和$cin$一样对空格免疫:

改进版$scanf$输入:$scanf("$ %$c", $&$x);$

没错,就是在%$c$之前加一个空格。这样的$scanf$和$cin$一样,对于无论多长的空格和换行都免疫。

2.一种坑有点大的读入([[$SDOI2006$]保安站岗](https://www.luogu.org/problem/P2458))

读题。嗯,先读入节点编号,再读入当前节点经费,再读入子节点数,再读入对应的子节点。

于是写了这个:
```cpp
scanf("%d%d%d", &x, &money[x], &m);
for (int i = 1; i <= m; i++) {
    scanf("%d", &y);
    son[x].push_back(y);
}
```
然后跑一下样例,发现答案不对,然后又在算法部分查错,死活查不出来,最后生无可恋,砸掉电脑。

这种情况最好要检查一下输入啊~输入是基础啊~(╯‵□′)╯︵┻━┻

在每一次读入时都输出$money[x]$,发现输出都是$0$那么说明问题就出在$money$数组的输入。

让我们来想象一个过程:程序把你的这几个输入同时存入,你的第一个数据正在存入$x$的过程中,你的第二个数据也正在存入$money[x]$的过程中。第二个数据要存入$money[x]$,就必须找到对应的$x$。

按理来说,第一个数据才是第二个数据所对应的$x$,但是第一个数据还没有存完,第二个数据又必须找到对应的$x$

于是它只有找上一次的$x$作为指针,于是就存到上一次的$x$所对应的值里去了。

不信的话在这个输入后加一个$printf("$%$d", money[x-1])$,那么输出肯定就对上输入数据了。

对于这个题来说,实际上可以用
```cpp
scanf("%d%d%d", &x, &money[i], &m);
```

但是如果有的题强制你先输入$x$,再输入$..[x]$之类的,就没办法啦╮(╯▽╰)╭

$3.$其他注意事项

有的大佬在有字符读入的题中,喜欢用$scanf$读入数字,然后用$cin$读入字符

这样也的确可以,但是有风险!!因为$scanf$和$cin$可就没有流同步啦~所以如果混用会有一定的风险。

本人在做骑士精神那道题时,就因为混用而出现了玄学$bug$,成功地爆$0$了~

不过当我将$scanf("$%$d",$&$t)$改成$cin>>t$后或者将$cin>>x$改成$scanf("$ %$c", $&$x)$,就是满分。

具体代码见讨论区~

-----------------------------------------------------------------------------------------------

总结:输入方面是许多人很少注意的地方,当你检查程序时,个人建议先检查输入输出。(~~虽然我从来没有这么做过~~)

如果本文有任何错误或者可以补充的地方,欢迎在下方评论区提出~

原文地址:https://www.cnblogs.com/66ccffxym/p/11373390.html

时间: 2024-11-05 20:25:43

C++的常用输入及其优化以及注意事项的相关文章

MyEclipse2013 常用设置毋宁优化

MyEclipse2013 常用设置与其优化 1:颜色设置-调整为适合阅读的浅绿色:   (1)Window->Preferences->General->Editors->Text Editors->  a.Backgroudcolors 背景颜色 设置为RGB(204,232,207)  b.Current linehighlight当前行高亮颜色 RGB (162,215,167)  (2)Window->Preferences->General->E

[转]MySQL性能调优与架构设计&mdash;&mdash;第11章 常用存储引擎优化

第11章 常用存储引擎优化 前言: MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.每一种存储引擎都有各自的特长,也都存在一定的短处.如何将各种存储引擎在自己的应用环境中结合使用,扬长避短,也是一门不太简单的学问.本章选择最为常用的两种存储引擎进行针对性的优化建议,希望能够对读者朋友有一定的帮助. 11.1 MyI SAM存储引擎优化 我们知道,MyISAM存储引擎是MySQL最为古老的存储引擎之一,也是最为流行的存储引擎之一.对

MySQL性能调优与架构设计——第11章 常用存储引擎优化

第11章 常用存储引擎优化 前言: MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.每一种存储引擎都有各自的特长,也都存在一定的短处.如何将各种存储引擎在自己的应用环境中结合使用,扬长避短,也是一门不太简单的学问.本章选择最为常用的两种存储引擎进行针对性的优化建议,希望能够对读者朋友有一定的帮助. 11.1 MyI SAM存储引擎优化 我们知道,MyISAM存储引擎是MySQL最为古老的存储引擎之一,也是最为流行的存储引擎之一.对

PHP常用的一些优化技巧

PHP常用的一些优化技巧 点击联系老杨 ecshop模板 php 优化技巧 老杨ecshop ecshop二次开发 2013-03-29 0 做为最流行的WEB语言, PHP他的突出优势就是其速度与效率.如果遇到维护原有效率不高的脚本,或者服务器负载较大,以及网络带宽不高等多种影响系统性能的瓶颈时,就需要我们对系统的内部环境经行调优.老杨ecshop二次开发一:PHP脚本优化      我下面说的几条PHP脚本级优化,你可以在优化时用到它们,这些技巧并不能让PHP运行速度变的更快,而只能使代码稍

常用最短路优化算法及例题(附模板)——-SPFA和Dijkstra

常用最短路算法——-SPFA和Dijkstra及其优化 这篇文章将简单讲解两个最常用的最短路优化算法,需要读者有一定的图论基础. 首先从DIJKSTRA讲起.常规的dijkstra算法复杂度较高,为O(n^2),因为要花大量时间来找当前已知的距顶点距离最小的值,所以用优先队列(值小的先出队列)来优化,可大大优化时间复杂度.STL中优先队列的操作单次复杂度为O(logN),所以经过优先队列优化的dijkstra时间复杂度会降到O(N*logN); 以下为核心部分代码: 1 struct pack{

常用输入字符流Reader

Reader是用于输入字符数据的,它所根据的 方法跟InputStream基本一样.它是所有输入字符流的抽象父类,因此不能直接构建Reader的实例,必须通过它的子类来构建.以下是几个常用的子类: 1.字符数组作为输入源--CharArrayReader CharArrayReader包含一个内部缓冲区,该缓冲区包括从流中读取的字符数组.所谓内存缓存区,就是对应了内存中存在的字符数组,因此可以根据字符数组来创建该类的实例.它有以下两个构造函数: CharArrayReader(char[] bu

输入的优化

读入整型时,输入优化可以节省不少时间 1 typedef type long long 2 // 这里以long long为例 3 type read() { 4 type x=0; int f=1; 5 char ch=getchar(); 6 while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();} 7 while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();

常用输入字节流InputStream

输入字节流InputStream的一系列实现,以下是五种较常用的子类 1.字节数组作为输入源--ByteArrayInputStream 该类包括两个构造方法 ByteArrayInputStream(byte[] buf); ByteArrayInputStream(byte[] buf,int offset,int length ); 该类重写了InputStream中的所有方法,因此我们可以调用其父类同名的方法进行读写操作. 下面是如何通过一个字节数组创建字节输入流的过程,并从输入流中读取

Mysql常用配置及优化

[client]# 该目录下的内容常用来进行localhost登陆,一般不需要修改port = 3306 # 端口号socket = /var/lib/mysql/mysql.sock # 套接字文件(localhost登陆会自动生成) [mysql]# 包含一些客户端mysql命令行的配置no-auto-rehash # 默认不自动补全 auto-rehash自动补全 [mysqld]# mysql优化的配置目录,除硬件和环境配置外,全部优化在此配置,# 一般服务器安装只有此配置目录user