原文地址:http://www.hankcs.com/program/cpp/cin-tie-with-sync_with_stdio-acceleration-input-and-output.html
http://www.clanfei.com/2012/03/235.html
在網上查看別人的ACM代碼時,發現別人輸入輸出語句用的總是scanf與printf,有點不解,還以為他們用的都是C語言,而非C++,但今天做的一道題(Sort):
發現與網上的其他高手使用完全相同的方法,使用scanf及printf的代碼提交后Accepted,而使用cin及cout的卻Time Limit Exceeded,代碼如下:
代碼一(Accepted):
- #include<iostream>
- using namespace std;
- bool a[1000001];
- int main()
- {
- int n, m, num, count;
- while(scanf("%d%d",&n,&m)!=EOF){
- memset(a, 0, sizeof(a));
- for(int i=0; i<n; i++){
- scanf("%d",&num);
- a[num + 500000] = 1;
- }
- count = 0;
- for(int j = 1000000; j >= 0; --j){
- if(a[j]){
- if(count == m - 1){
- printf("%d\n",j-500000);
- break;
- }
- printf("%d ",j-500000);
- count++;
- }
- }
- }
- return 0;
- }
代碼二(Time Limit Exceeded):
- #include<iostream>
- using namespace std;
- bool a[1000001];
- int main()
- {
- int n, m, num, count;
- while(cin >> n >> m){
- memset(a, 0, sizeof(a));
- for(int i=0; i<n; i++){
- cin >> num;
- a[num + 500000] = 1;
- }
- count = 0;
- for(int j = 1000000; j >= 0; --j){
- if(a[j]){
- if(count == m - 1){
- cout << j - 500000 << endl;
- break;
- }
- cout << j - 500000 << " ";
- count++;
- }
- }
- }
- return 0;
- }
可以看出,代碼思路完全一樣,只是輸入輸出方法不同,問過老師,加上這一句代碼后使用cin及cout也可以Accepted:
- std::ios::sync_with_stdio(false);
百 度了一下,原來而cin,cout之所以效率低,是因為先把要輸出的東西存入緩沖區,再輸出,導致效率降低,而這段語句可以來打消iostream的輸入 輸出緩存,可以節省許多時間,使效率與scanf與printf相差無幾,還有應注意的是scanf與printf使用的頭文件應是stdio.h而不是 iostream。
我是怎么在不知道這一對函數的情況下活到今天的,以前碰到cin TLE的時候總是傻乎乎地改成scanf,甚至還相信過C++在IO方面效率低下的鬼話,殊不知這只是C++為了兼容C而采取的保守措施。
tie
tie是將兩個stream綁定的函數,空參數的話返回當前的輸出流指針。
- #include <iostream>
- #include <fstream>
- ///////////////////////////SubMain//////////////////////////////////
- int main(int argc, char *argv[])
- {
- std::ostream *prevstr;
- std::ofstream ofs;
- ofs.open("test.txt");
- std::cout << "tie example:\n"; // 直接輸出到屏幕
- *std::cin.tie() << "This is inserted into cout\n"; // 空參數調用返回默認的output stream,也就是cout
- prevstr = std::cin.tie(&ofs); // cin綁定ofs,返回原來的output stream
- *std::cin.tie() << "This is inserted into the file\n"; // ofs,輸出到文件
- std::cin.tie(prevstr); // 恢復
- ofs.close();
- system("pause");
- return 0;
- }
- ///////////////////////////End Sub//////////////////////////////////
輸出:
- tie example:
- This is inserted into cout
- 請按任意鍵繼續. . .
同時當前目錄下的test.txt輸出:
- This is inserted into the file
sync_with_stdio
這個函數是一個“是否兼容stdio”的開關,C++為了兼容C,保證程序在使用了std::printf和std::cout的時候不發生混亂,將輸出流綁到了一起。
應用
在ACM里,經常出現 數據集超大造成 cin TLE的情況。這時候大部分人(包括原來我也是)認為這是cin的效率不及scanf的錯,甚至還上升到C語言和C++語言的執行效率層面的無聊爭論。其 實像上文所說,這只是C++為了兼容而采取的保守措施。我們可以在IO之前將stdio解除綁定,這樣做了之后要注意不要同時混用cout和printf 之類。
在默認的情況下cin綁定的是cout,每次執行 << 操作符的時候都要調用flush,這樣會增加IO負擔。可以通過tie(0)(0表示NULL)來解除cin與cout的綁定,進一步加快執行效率。
如下所示:
- #include <iostream>
- int main()
- {
- std::ios::sync_with_stdio(false);
- std::cin.tie(0);
- // IO
- }