- #include<cstdio>
- #include<iostream>
- #include<cctype>
- using namespace std;
- int read()
- {
- int s = 0, f = 1;
- char ch = getchar();
- while(!isdigit(ch)) {
- if(ch == '-') f = -1;
- ch = getchar();
- }
- while(isdigit(ch)) {
- s = s * 10 + ch - '0';
- ch = getchar();
- }
- return s * f;
- }
- void write(int x)
- {
- if(x < 0) {
- putchar('-');
- x = -x;
- }
- if(x > 9)
- write(x/10);
- putchar(x % 10 + '0');
- return;
- }
- int main()
- {
- int a;
- a = read();
- write(a);
- return 0;
- }
一些問題:
1. 快讀快寫比標准輸入輸出流以及C的格式化輸入輸出要快,主要是由於直接利用了單個字符操作,並且適用范圍僅限所定義的返回類型與輸出類型,犧牲了標准輸入輸出的普適性而換取了效率,在算法競賽中具有廣泛的應用空間。
2. 快讀、快寫函數的實現分別用到了循環和遞歸,從理論上講無法完成內聯,inline建議不會被編譯器采納;通過在vijos上對某一需要大量輸入的題目使用快讀進行測試,可以發現read()前加入或不加入inline的效率幾乎相同。由此可以判斷inline大概率被忽略,或是函數調用和返回的時間微不足道,個人認為inline沒有必要。(不理解的同學可從資料和各大博客了解內聯函數的相關知識)
3. 該方法利用了cctype庫中的字符判斷函數isdigit(),其效率與手寫ASCII碼判斷幾乎不相上下,甚至更快,可以說同時實現了簡潔與快捷,建議使用。
4. 理論上效率較高的寫法是將read中所定義的變量加入寄存器建議,但是實測的效率相差並不大。依然有指令被編譯器忽略的可能性,因此加不加入就看自己的想法了。
5. int read(void)函數也可以寫成void read(&int)的形式(對地址進行直接賦值操作),效率方面沒有太大差別,可以按照個人愛好采用不同風格。
6. 一種使用fread()函數可以進一步顯著提升讀入效率,但寫法較為復雜,且需要額外開辟內存,出錯率高,在OI中用途有限,有興趣的同學可以自行學習了解。
太原五中
袁盛琪
2019年3月26日
----------------------------------------------
2019.7.7 做一個補充
- template <typename T>
- void read(T &x) {
- x = 0;
- int f = 1;
- char ch = getchar();
- while (!isdigit(ch)) {
- if (ch == '-') f = -1;
- ch = getchar();
- }
- while (isdigit(ch)) {
- x = x * 10 + (ch ^ 48);
- ch = getchar();
- }
- x *= f;
- return;
- }
以上是使用模板template的快速讀入。它可以讀取任何格式的整型數據。
再說明一個以前留下的小問題:register編譯建議是在每個函數進程中重新定義的,即便是讀入int64范圍的數據,函數變量也最多會迭代20次左右,每次把它定義在寄存器里其實有些雞肋。
----------------------------------------------
附上使用模板的快寫。
- template <typename T>
- void write(T x)
- {
- if(x < 0) {
- putchar('-');
- x = -x;
- }
- if(x > 9)
- write(x/10);
- putchar(x % 10 + '0');
- return;
- }