【NOIP復賽篇3】文件輸入輸出和構造數據

上篇文章 中,我們簡單地提到過使用freopen的方式進行文件的輸入輸出,這篇文章我們再介紹一下其他幾種文件的輸入輸出方式,接著再談談如何構造數據檢測程序是否正確。

一、 文件輸入輸出

1、標準輸入輸出

我們最常接觸到的程序的輸入輸出,是直接在命令行窗口(Dos窗口)進行輸入輸出的,也可以直接地理解為,需要我們在命令行中用鍵盤輸入,同時結果也在命令行中顯示的方式。這樣的一種方式,我們稱之為標準輸入輸出。

標準輸入輸出

標準輸入輸出的優缺點都很明顯,優點是簡單方便,直觀;缺點是需要手工操作,對于復雜數據比較麻煩,難以批量處理數據。在NOIP/NOI或ACM比賽中,因為涉及到的程序、輸入數據特別多,因此不可能使用標準輸入輸出進行校驗和評分,因此標準輸入輸出一般都是用于自己調試數據時使用,在比賽中都是需要使用文件輸入輸出。下面將介紹幾種常用的文件輸入輸出方式。

2、freopen文件輸入輸出

這是使用了文件的重定向方式,C++利用freopen函數將stdin和stdout重新定向到相關的文件,使原來的標準輸入輸出變成了文件輸入輸出。也就是說,如果之前我們有一段已經用標準輸入輸出的代碼,我們并不需要更改任何代碼,只需要在原來的基礎上加上freopen語句,重新定向一下就可以了,因此這是一種非常簡單、快捷的方式。

// 假設輸入文件是input.in,輸出文件是output.out,同時需要注意的是OI比賽中要求文件名不能帶目錄,即要求輸入文件應該與源代碼在同一目錄下

freopen("input.in", "r", stdin);? ? ? ? // 輸入文件

freopen("output.out", "w", stdout); // 輸出文件

freopen()函數有三個參數,前兩個是需要『雙引號』的。第一個參數是『輸入文件/輸出文件』;第二個參數『r』表示讀入,是read的縮寫,『w』表示寫入,是write的縮寫;第三個參數是『標準輸入/標準輸出』,即是stdin,stdout。

如:a+b程序

//標準輸入輸出

#include<iostream>

using namespace std;

int main(){

int a, b;

cin >> a >> b;

cout << a+b;

return 0;

}

freopen()重定向輸入輸出,只需要在以上代碼的基礎上添加兩句代碼即可,同時因為freopen函數是在cstdio這個庫中,因此在書寫時,應該引入cstdio庫。

#include <iostream>

#include <cstdio>? // 需要包含這個庫

using namespace std;

int main(){

freopen("input.in", "r", stdin);? ? ? ? // 輸入文件

freopen("output.out", "w", stdout); // 輸出文件

int a, b;

cin >> a >> b;

cout << a+b;

return 0;

}

3、文件流輸入輸入(fstream)

『流』這是一個講起來比較復雜的概念,我們暫且不需要理解和掌握,知道就可以了,隨著后面的深入學習我們會逐步理解。其實『流』在我們之前就已經接觸到了,譬如cin,cout本身也是一種流的輸入輸出,我們知道它是C++中的一種特性就可以了。

流式文件的操作一般包含兩種,一個是stream類的流文件,另一個是文件指針FILE,涉及到指針的問題又比較復雜,所以我們重點介紹一下stream類的流文件的處理。

我們同樣來看案例代碼,進行對比。(a+b問題,標準輸入輸出同上)

#include <iostream>

#include <fstream>? ? // f是file的縮寫,stream是流,合起來就是文件流

using namespace std;

ifstream fin("input.in");? ? ? // 輸入文件

ofstream fout("output.out");? //輸出文件

int main(){

int a, b;

fin >> a >> b;? ? // cin變成了fin

fout << a+b;? ? // cout 變成了fout

return 0;

}

對上述代碼的補充說明:

1、需要包含fstream庫,即#include <fstream>,f是file的縮寫,stream是流,合起來就是流文件,很好記憶。

2、ifstream,i是in的縮寫,輸入流文件;同樣的,ofstream,o是out的縮寫,輸出流文件。并且特別要注意的是,ifstream和ofstream,一般寫在函數外面,因為是全局使用的,而且建議最好就直接寫在using namespace std 之后。

3、fin/fout,僅僅是一個變量名,可以更換,但是推薦使用這個,養成良好的代碼習慣。fin/fout與cin/cout用法基本上是一致的。

4、代碼中可以不出現關閉文件代碼,因為程序結束后會自動關閉。

4、輸入輸出速度問題

由于兼容性等歷史問題,文件操作時,C++的cin/cout要保證與printf/scanf同步,因此cin/cout的效率會降低。雖然我們可以使用關閉同步功能(iso::sync_with_stdio(false);)來提高效率,但是在不同的C++編譯器中,它們效率表現不太一樣,因此我們認為它的效率是不穩定的。所以為了保障輸入輸出的效率,在題目中有大規模數據輸入輸出時,我們建議使用scanf,printf,而不用cin,cout。

cin,cout雖然效率不穩定,但是相對比較簡單,不需要我們去記各種格式,所以如果依舊不想記憶各種格式的同學,可以選擇用fstream的方式進行文件操作。scanf,printf雖然效率高,但是有時要記的格式有點多,不過其實用多了就會很熟練了。OI比賽中一般都是只有一個輸入、輸出文件,因此用freopen+scanf/printf的方式也挺好的。但是就強烈不建議,使用freopen+cin/cout的方式。

二、構造數據

1、為什么要構造數據

在OI/ACM比賽中,我們的程序都是基于『黑盒測試』的。也就是程序的正確與否,比賽并不關心,比賽也并不關心你使用了什么方法。只要你能在規定的時間內,把問題解決就可以了。那么如何評判是否是正確答案呢?一般都是出題人會用若干個輸入數據,然后運行代碼,將得出的結果與答案進行比對,絕大多數情況下,都是將你的程序的結果與答案進行逐行比對,多一個空格/換行,也不正確,因此需要特別注意輸出時的格式。

對于OI和ACM有所區別的是,OI允許非正確解(沒能通過全部測試點)得分,OI會按通過點得分,通過幾個點就得到幾個點的分數,因此在OI界有非常多的『騙分』。而在ACM比賽中,只允許正解得分(通過全部測試點),要么是滿分,要么零分(和提交次數有關,多提交會扣分)。當然啦,我們比賽中,我們合理利用所有能用的方法(作弊的拖出去槍斃),盡可能拿到更多的分,本身就是合情合理的,你在騙分,出題人在想怎么防你騙分,本身也是一種斗智斗勇,想騙也不是那么容易騙的,這也是一種能力。

那么針對『黑盒測試』,我們想要通過更多的測試點,也就是要求我們考慮問題更加全面,我們也就需要在寫完代碼之后,自己構造數據,進行測試。對于選手來說,如何測試是一樣非常重要的能力,同樣對于程序員來說也是如此,這是一項基本功,很難一下子提高,需要不斷積累和總結。

2、怎么構造數據

構造數據需要考慮幾個要點,第一,盡可能全面地考慮問題;第二,考慮邊界、臨界值;第三,考慮大數據;第四,考慮特殊值,極端數據;第五,隨機數據。

最最簡單的檢測方法,就是自己根據上述幾個要點,自己構造數據,用程序進行檢測,如果出現不通過的情況,可以結合前面的調試程序的方法去改正和調試。還有比較特殊的一個方法,就是構造隨機數,然后進行數據的『對拍』。所謂對拍,即是用一個保證正確的方法(也許時間復雜度比較大)得出的結果,與你所謂的『正解』結果進行比對。如果對拍了很多數據都能通過,基本上就是正解了,對拍也是一樣很重要的技能。關于對拍的方法和技巧,我們會在下一次課再介紹。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容

  • 淺談C++常用輸入輸出 在編寫C++程序的時候,經常因為輸入輸出頭疼,所以在這里做一個小結,記錄一下常用的輸入輸出...
    MinoyJet閱讀 3,758評論 0 6
  • C/C++輸入輸出流總結 前兩天寫C++實習作業,突然發現I/O是那么的陌生,打了好長時間的文件都沒有打開,今天終...
    LuckTime閱讀 1,747評論 0 6
  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,045評論 6 13
  • 1. 流 流:數據從一個對象到另一個對象的傳輸。 功能:標準輸入輸出+文件處理 分類含義文本流一串ASCII字符二...
    jdzhangxin閱讀 1,399評論 0 4
  • 明天要出趟遠門,心里亂糟糟的,我不是個特別膽兒大的人,也不常一個人睡,所以啊,真是有些憂心。還要去學校辦事,...
    小鎮Y胖Y閱讀 194評論 0 0