讀入優化&輸出優化


注意了注意了注意了,重要的事情說3遍,這個東西是騙分神器,騙分神器,騙分神器!!!
眾所周知:scanf比cin快得多,printf比cout快得多,如果你不知道就……就現在知道了
那有沒有更快的呢?當然。
請看:


我懵逼了,至於慢近100ms嗎? 

好吧,這就是讀入優化的效果,在數據很恐怖的情況下能比scanf多過1-5個點……
比如說這種:

都說了要讀入優化你還不讀入優化,那不是找死嗎……

前面都是廢話,現在開始說正事

讀入優化

首先,讀入優化這里是只是針對整數,getchar讀字符是非常快的,所以我們就用getchar了。(下面都假設輸入的數為x)

負數處理

很簡單,用一個標志變量f,開始時為1,當讀入了’-’時,f變為-1,最后x*=f即可

絕對值部分處理

顯然getchar每次只能讀一位,所以,每當讀了一位時x*=10,為這一位“留位置”。
舉個例子:現在讀入了123,x為123,再讀入了一個4,x*=10,變為了1230,現在它的最后一位空出來了,正好留給4,x+=4,x就變為了1234,當然,這里的’4’是char類型,需要減去’0’才是4,即:x=x*10+s-'0'(s為當前輸入的字符)

關於細節

很多時候是有多余空格或者其他的亂碼字符輸入,為了防止bug,我們要嚴謹~詳見代碼。

代碼

 1 void read(int &x)//'&'表示引用,也就是說x是一個實參,在函數中改變了x的值就意味着在外面x的值也會被改變
 2 {
 3     int f=1;//標記正負
 4     x=0;//歸零(這就是潛在bug,有可能傳進來時x沒有歸零)
 5     char s=getchar();//讀入第一個字符
 6     while(s<'0'||s>'9')//不是數字字符
 7     {
 8         if(s=='-')//不能直接把f=-1,有可能輸入的不是'-'而是其他亂七八糟的東西
 9             f=-1;
10         s=getchar();//繼續讀
11     }
12     while(s>='0'&&s<='9')//是字符(一旦不是字符就意味着輸入結束了)
13     {
14         x=x*10+s-'0';
15         s=getchar();
16     }
17     x*=f;//改變正負
18 }

簡潔一些:

1 void read(int &x)
2 {
3     int f=1;x=0;char s=getchar();
4     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
5     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
6     x*=f;
7 }

這就是完整的讀入優化了,你可以直接這樣用:

1 int N;
2 read(N);

當然還有更裝逼的代碼:

1 #define num ch-'0'
2 void get(int &res){
3     char ch;bool flag=0;
4     while(!isdigit(ch=getchar()))
5         (ch=='-')&&(flag=true);
6     for(res=num;isdigit(ch=getchar());res=res*10+num);
7     (flag)&&(res=-res);
8 }

這個就真的很跳了。
首先:isdigit是判斷一個字符是否為數字字符,需要頭文件#include<cctype>,剛剛忘了說,getchar需要cstdio。
然后,那個詭異的(ch=='-')&&(flag=true)和(flag)&&(res=-res);是個什么玩意?我們發揮聰明才智,想起&&是“短路運算符”,短路運算符是啥?就是看到第一個條件錯誤就不會執行第二個條件,直接跳過了,所以這兩句代碼就不難理解了,唯一顛覆寶寶們的認知的是&&可以脫離if和return什么的直接用……

輸出優化

如果有50%的人知道輸入優化,那知道輸出優化的最多不過20%,輸出還能怎么優化?putchar啊!putchar是比printf快的。(下面都假設輸出的數為x)
ps:居然還有putchar這種東西?!

負數處理

輸出就簡單了,如果是負數,直接putchar('-');x=-x;即可,不解釋。

絕對值部分處理

這里是不是還是用循環呢?答案是——否定的,為了極致的速度,我們用遞歸!遞歸什么?遞歸下一位啊,即x/10,然后,注意邊界,x要>9才能繼續遞歸,否則要輸出x%10(因為還有最后一位)。

關於細節

無……

代碼

 1 void print(int x)//這里當然不用實參
 2 {
 3     if(x<0)//負數
 4     {
 5         putchar('-');
 6         x=-x;
 7     }
 8     if(x>9)//只要x還是2位數或更多就繼續分解
 9         print(x/10);//這里遞歸完后棧里面x的每一位是倒過來的(關於遞歸,我也實在解釋不清楚,各位去看看神犇們的遞歸解釋吧)
10     putchar(x%10+'0');//輸出(要把int型變為char型,加'0'即可)
11 }

至於輸出優化,目前還沒發現什么太跳的,畢竟寫輸出優化的就少。

對比

為了能看出優勢,我做了一個對比: 
Test.cpp:

 1 #include<cstdio>
 2 #include<ctime>
 3 #include<windows.h>
 4 using namespace std;
 5 #define TIMES 1000000
 6 double A[5];
 7 void print(int x)
 8 {
 9     if(x<0)putchar('-'),x=-x;
10     if(x>9)print(x/10);
11     putchar(x%10+'0');
12 }
13 void read(int &x)
14 {
15     int f=1;x=0;char s=getchar();
16     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
17     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
18     x*=f;
19 }
20 int main()
21 {
22     freopen("in.txt","r",stdin);
23     freopen("111.txt","w",stdout);
24     int a;
25     double t1,t2;
26     t1=clock();
27     for(int i=1;i<=TIMES;i++)
28         scanf("%d",&a);
29     t2=clock();
30     A[1]=(t2-t1)/1000;
31     t1=clock();
32     for(int i=1;i<=TIMES;i++)
33         read(a);
34     t2=clock();
35     A[2]=(t2-t1)/1000;
36     t1=clock();
37     for(int i=1;i<=TIMES;i++)
38         printf("%d",a);
39     t2=clock();
40     A[3]=(t2-t1)/1000;
41     t1=clock();
42     for(int i=1;i<=TIMES;i++)
43         print(a);
44     t2=clock();
45     A[4]=(t2-t1)/1000;
46     fclose(stdout);//為了不輸出前面一堆東西
47     freopen("out.txt","w",stdout);
48     printf("Scanf:  %.4lf S\n",A[1]);
49     printf("Read:   %.4lf S\n",A[2]);
50     printf("Printf: %.4lf S\n",A[3]);
51     printf("Print:  %.4lf S",A[4]);
52 }

Data.cpp:

 1 #include<cstdio>
 2 #include<ctime>
 3 #include<cstdlib>
 4 #define TIMES 1000000
 5 #define MAXN 100000
 6 int main()
 7 {
 8     srand(time(NULL));
 9     freopen("in.txt","w",stdout);
10     for(int i=1;i<=TIMES*2;i++)
11     {
12         if(rand()%2)
13             printf("-");
14         printf("%d\n",rand()%MAXN);
15     }
16 }

如果你想測cin,cout,自己試試吧…… 
以下是我的測試結果(測5次,數據一模一樣):

次數        scanf耗時              read耗時                 printf耗時              print耗時
1             0.2960 S                0.0790 S                0.1870 S               0.0630 S
2             0.2960 S                0.0940 S                0.1720 S               0.0630 S
3             0.2810 S                0.0780 S                0.1870 S               0.0630 S
4             0.2960 S                0.0790 S                0.1870 S               0.0470 S
5             0.2970 S                0.0780 S                0.1720 S               0.0630 S


這里用了1000000組數據,輸入優化比scanf快了約0.2秒,也就是說,每50萬組數據讀入優化要快0.1秒(100ms),剛好符合了最開始的數據范圍。



作者:∞∑
來源:CSDN
原文:https://blog.csdn.net/c20190102/article/details/69710341
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM