论整数输入优化

15 篇文章 7 订阅
10 篇文章 0 订阅

背景

前些天发现了写读入优化和不写读入优化的区别。。。

别人的代码:

我的代码:

我似乎发现了什么东西。。。

然后我点进第一名的代码一看:

void get(int &res){ 
    char ch;bool flag=0; 
    while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true); 
    for(res=num;isdigit(ch=getchar());res=res*10+num); 
    (flag)&&(res=-res); 
}

当时我是懵逼的。小小一个函数,竟然可以快那么多!
在分析函数的时候,我弄不明白(ch=='-')&&(flag=true)(flag)&&(res=-res)是什么意思,然后我就分析了一下:

(A)&&(B)是先判断A是否成立,如果A成立,B为执行的语句(如a=b),就执行B语句。

这就是读入优化
然后我搜集了一下资料,这一种写法是比较装逼,会遭雷劈的写法,所以我们还是脚踏实地,从零开始。

读入优化的原理与实现

C++里有很多种输入方式,我们最常用的是scanf和cin,因为这两个函数比较好用一些。除此之外,还有一些读入字符的函数,给大家普及一下:

#include<cstdio>
#include<cstring>
int main()
{
    char c[];
    int len=strlen(c);//获取c数组的长度,需要用#include<cstring>头文件

    gets(c);//读入一行字符串,遇到回车后停止,可以无限读取,不会判断上限,所以容易溢出。而且该函数,这个函数在ISO/IEC 9899 2011(C11)标准中被移除。

    fgets(c,len,stdin);//和gets函数差不多,读取长度超过len或者遇到回车都会停下来,所以每次最多读取len-1个(因为字符数组最后一个'\0'占位)

    c[0]=getchar();//像scanf一样,读入一个字符,并返回这个字符,可以直接赋值,需要用#include<cstdio>头文件。和scanf不同的是,该函数是非缓冲输入函数,也就意味着它比scanf更快。

    c[0]=getch();//直接读入一个字符,而没有回显(但在linux系统下有回显)。也就是说,你读入了一个字符,它不会在界面里显示而是直接读入这个字符,getch也会直接返回这个字符。比如说你写了一个程序小游戏,你肯定不希望看到wasd满天飞,所以就用getch。需要#include<conio.h>头文件。同样,它没有缓冲。
}

getchar比scanf更快。

我们可不可以用getchar来改进我们的输入呢?

当然是可以的。首先getchar是一个一个字符读入的,所以我们要一个一个读入,但是我们要给他进位,就要乘以10,因为它是ASCII码,就要给它减个‘0’。比如是字符‘1’,‘1’-‘0’就为数字1.

理论了过后,我们就来模拟一下过程:
假设输入2018。

  1. 程序读入字符‘2’,‘2’-‘0’得数字2,ans=0*10+2=2.
  2. 程序读入字符‘0’,‘0’-‘0’得数字0,ans=2*10+0=20.
  3. 程序读入字符‘1’,‘1’-‘0’得数字1,ans=20*10+1=201.
  4. 程序读入字符‘8’,‘8’-‘0’得数字8,ans=201*10+8=2018.

基本上就是这样,不给大家一一举例了。
依照以上的逻辑,ans=ans*10+ch-'0'

可是有的时候输入这样子:
123 456 789

每两个数之间有空格,这又怎么办呢?

哦,那么就先把数字前的空格读完,即一直读入,直到出现数字为止。
到此我们就可以给出第一代的程序了:

void get(int &a)
{
    a=0;
    char ch;
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') a=a*10+ch-'0',ch=getchar();
}
遇到负数怎么处理?

相信有些读者会说直接将数字乘以-1,可是一开始数字为0,乘以任何数都为0,肯定是不能这样做的。
那只要在最开始设置标记为1,读整数之前,如果有符号(‘-’),就设置标记为-1,最终用数字乘以标记即可。

肯定有人要说了,那开头的isdigit函数是什么鬼?
其实这个函数就是检测字符为不为阿拉伯数字0到9,所以我们也可以用这个函数减小代码量。
注:要用#include<iostream>头文件。

代码

最终有两种代码。

void get(int &p){
    int flag=1;char ch;
    for(p=0;!isdigit(ch);ch=getchar()) if(ch=='-') flag=-1;
    for(;isdigit(ch);ch=getchar()) p=p*10+ch-'0';
    p*=flag;
}

这种代码直接get(int)即可。

int get(){
    int flag=1,p=0;char ch;
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') flag=-1;
    for(;isdigit(ch);ch=getchar()) p=p*10+ch-'0';
    return p*flag;
}

这种代码int=get()即可。

验证读入优化的效率

数据制造程序

用freopen生成1000000个数的文本,并分别用scanf,cin和读入优化读入。

#include<cstdio>
const int N=1000000;
int main()  
{  
    freopen("test.txt","w",stdout);//保存输出结果为文件
    for(int i=1;i<=4;i++)//测试直接get,赋值get,scanf,cin四种读入程序
    {
        for(int j=1;j<=N;j++)  
            printf("%d ",i);
        puts("");
    }
} 
测试程序
#include<ctime>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1000000;
void get_tradition(int &p){
    int flag=1;char ch;
    for(p=0;!isdigit(ch);ch=getchar()) if(ch=='-') flag=-1;
    for(;isdigit(ch);ch=getchar()) p=p*10+ch-'0';
    p*=flag;
}
int get_assignment(){
    int flag=1,p=0;char ch;
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') flag=-1;
    for(;isdigit(ch);ch=getchar()) p=p*10+ch-'0';
    return p*flag;
}
int main()
{
    freopen("test.txt","r",stdin);//读入测试文件
    freopen("test.out","w",stdout);
    int x;
    double A[4];
    double t1=clock();
    for(int i=1;i<=N;i++)
        get_tradition(x);
    double t2=clock();
    A[0]=(t2-t1)/1000;
    t1=clock();
    for(int i=1;i<=N;i++)
        x=get_assignment();
    t2=clock();
    A[1]=(t2-t1)/1000;
    t1=clock();
    for(int i=1;i<=N;i++)
        scanf("%d",&x);
    t2=clock();
    A[2]=(t2-t1)/1000;
    t1=clock();
    for(int i=1;i<=N;i++)
        cin>>x;
    t2=clock();
    A[3]=(t2-t1)/1000;
    fclose(stdout);
    freopen("Answer.out","w",stdout);
    printf("When number is %d,\n",N);
    printf("get_tradition   took %.3lf second(s)\n",A[0]);
    printf("get_assignment  took %.3lf second(s)\n",A[1]);
    printf("scanf           took %.3lf second(s)\n",A[2]);
    printf("cin             took %.3lf second(s)\n",A[3]);
}

总结

When number is 1000000,
get_tradition took 0.078 second(s)
get_assignment took 0.062 second(s)
scanf took 0.297 second(s)
cin took 2.063 second(s)

cena

作死,n=100000000时,

表示cin无语。。。

读入优化并不是装逼,而真正可以节省时间。所以读入优化是针对数据比较多的题目而言的,所以让我们养成写读入优化的习惯!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值