NO.31十六届蓝桥杯备战|输入时的特殊技巧|scanfprintf和cincout对比|ios::s ...

金歌  论坛元老 | 2025-3-27 03:21:06 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1814|帖子 1814|积分 5442

含空格字符串的特殊处理方式

根据我们现在掌握的知识,含空格的字符串,如要读取有 fgets 、 scanf 、getchar 、 getline 四种⽅式解决,但是有时候,根据题⽬的情况,不⼀定⾮要完整的读取这个带空格的字符串,⽽是将字符串中空格隔开的每⼀个字符串,当做⼀个单词处理更⽅便,也制止了读取带空格字符串的各种问题。
B2109 统计数字字符个数 - 洛谷

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 265;
  4. char a[N] = {0};
  5. int main()
  6. {
  7.     ios::sync_with_stdio(false);
  8.     cin.tie(nullptr);
  9.     string s;
  10.     getline(cin, s);
  11.     int cnt = 0;
  12.     for (auto e : s)
  13.     {
  14.         if (isdigit(e))
  15.             cnt++;
  16.     }
  17.     cout << cnt << endl;
  18.    
  19.     return 0;
  20. }
复制代码
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 265;
  4. char a[N] = {0};
  5. int main()
  6. {
  7.     ios::sync_with_stdio(false);
  8.     cin.tie(nullptr);
  9.     string s;
  10.     int cnt = 0;
  11.     while (cin >> s)
  12.     {
  13.         for (auto e : s)
  14.         {
  15.             if (isdigit(e))
  16.                 cnt++;
  17.         }  
  18.     }
  19.     cout << cnt << endl;
  20.    
  21.     return 0;
  22. }
复制代码
数字的特殊处理⽅式

当我们程序运⾏的时候,在控制台输⼊ 123 的时候,这时的 123 是三个字符, 123 是⼀个字符序列,程序会根据代码中的数据类型,可能将 123 解析成整型,也可能将 123 解析成字符串
  1. int num = 0;  
  2. cin >> num;//输⼊123, 就被解析成整数  
  3. string s;  
  4. cin >> s; //输⼊123, 就被解析成字符串
复制代码
这⾥的解析的⽅式,主要是依赖编译器对变量类型的识别,根据类型再将读取字符串数据转化成对应类型的数据。
我们在写代码的时候,应该根据实际的情况,来决定如何处理输⼊的内容
小乐乐改数字_牛客题霸_牛客网

  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4.   
  5. int main() {
  6.     int n;
  7.     cin >> n;
  8.     int i = 0;
  9.     int ret = 0;
  10.     while (n)
  11.     {
  12.         if (n % 10 % 2)
  13.             ret += 1 * pow(10, i);
  14.         //else
  15.         //    ret += 0 * pow(10, i);
  16.         n /= 10;
  17.         i++;
  18.     }
  19.     cout << ret << endl;
  20.    
  21.     return 0;
  22. }
复制代码
  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4.   
  5. int main() {
  6.     string s;
  7.     cin >> s;
  8.     int i = 0;
  9.     for (i = 0; i < s.size(); i++)
  10.     {
  11.         if (s[i] % 2)
  12.             s[i] = '1';
  13.         else
  14.             s[i] = '0';
  15.     }
  16.     cout << stoi(s) << endl;
  17.   
  18.     return 0;
  19. }
复制代码
scanf/printf和cin/cout的对⽐

scanf 和 printf 是C语⾔中的标准输⼊输出函数,⽽ cin 和 cout 是C++语⾔中的标准输⼊输出流对象。它们各⾃有优缺点,团体上来说 cin 和 cout 会更加⽅便,但有时候我们也不得不使⽤ scanf 和 printf 。
格式控制差异



  • scanf 和 printf 不能⾃动识别输⼊数据的类型,必要⼿动指定格式字符串,容易出现格式错误。开发者必要确保格式字符串与变量类型匹配,否则会导致未界说⾏为。
  • cin 和 cout 会根据变量类型⾃动处理输⼊输出,制止格式化错误。相对 scanf 和 printf ⽽且,C++的 cin 和 cout 更加易⽤。
  • scanf 和 printf :格式化输出更正确直观,特殊得当复杂格式的输⼊输出,⽐如:在要求指定格式输出的时候, printf 函数就⽐ cout 更加⽅便和灵活。
  1. #include <cstdio>  
  2. #include <iostream>
  3. using namespace std;  
  4. int main()  
  5. {  
  6.         float a = 3.50;  
  7.         double d = 16.50;  
  8.        
  9.         cout << "cout: " <<a << " "<< d <<endl;  
  10.         printf("printf: %f %lf\n", a, d);  
  11.        
  12.         return 0;  
  13. }
复制代码


  • cout 默认不会输出六位⼩数,⾃动忽略⼩数点后多余的 0 , printf 函数打印浮点数的时候,⼩数点默认打印6位。
  • cout 在输出的时候不必要指定格式, printf 则必要明白的格式。
性能差异

案例演⽰

结论: scanf 和 printf 通常⽐ cin 和 cout 快。
缘故原由: cin 和 cout 由于要考虑兼容C语⾔的输⼊和输出,封装实现的更加复杂,通常⽐scanf 和 printf 稍慢,但这种差异在⼤多数应⽤场景中可以忽略不计。
但是在竞赛的题⽬中,尤其是当输⼊、输出数据量较⼤时,使⽤ cin 和 cout 完成输⼊输出,常常会出现 Time Limit Exceeded 的情况。⽽ scanf 和 printf 就不存在类似的问题。
数字游戏

  1. #include <iostream>
  2. using namespace std;
  3. int t, x;
  4. int main()
  5. {
  6.     cin >> t;
  7.     while (t--)
  8.     {
  9.         cin >> x;
  10.         int ret = 0;
  11.         while (x)
  12.         {
  13.             int count = 0, high
  14.             = 0;
  15.             int tmp = x;
  16.             while (tmp)
  17.             {
  18.                 //计算最右边的1代表的值
  19.                 int low = tmp & -
  20.                 tmp;
  21.                 //如果low中剩余的1就是最后⼀个1
  22.                 //就是最左边的1
  23.                 if (tmp == low)
  24.                 {
  25.                     high = low;
  26.                 }
  27.                 //去掉最右边的1
  28.                 tmp -= low;
  29.                 count++;
  30.             }
  31.             if (count % 2 == 0)
  32.             {
  33.                 x -= high;
  34.             }
  35.             else
  36.             {
  37.                 x ^= 1;
  38.             }
  39.             ret++;
  40.         }
  41.         cout << ret << endl;
  42.     }
  43.     return 0;
  44. }
复制代码

  1. #include <iostream>
  2. using namespace std;
  3. int t, x;
  4. int main()
  5. {
  6.     scanf("%d", &t);
  7.     while (t--)
  8.     {
  9.         scanf("%d", &x);
  10.         int ret = 0;
  11.         while (x)
  12.         {
  13.             int count = 0, high = 0;
  14.             int tmp = x;
  15.             while (tmp)
  16.             {
  17.                 //计算最右边的1代表的值
  18.                 int low = tmp & -
  19.                 tmp;
  20.                 //如果low中剩余的1就是最后⼀个1
  21.                 //就是最左边的1
  22.                 if (tmp == low)
  23.                 {
  24.                     high = low;
  25.                 }
  26.                 //去掉最右边的1
  27.                 tmp -= low;
  28.                 count++;
  29.             }
  30.             if (count % 2 == 0)
  31.             {
  32.                 x -= high;
  33.             }
  34.             else
  35.             {
  36.                 x ^= 1;
  37.             }
  38.             ret++;
  39.         }
  40.         printf("%d\n", ret);
  41.     }
  42.     return 0;
  43. }
复制代码

P1923 【深基9.例4】求第 k 小的数 - 洛谷

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. using namespace std;
  5. const int N = 5000010;
  6. int arr[N];
  7. int main()
  8. {
  9.     int n, k;
  10.     cin >> n >> k;
  11.     for (int i = 0; i < n; i++)
  12.     {
  13.         cin >> arr[i];
  14.     }
  15.     sort(arr, arr + n);
  16.     cout << arr[k] << endl;
  17.    
  18.     return 0;
  19. }
复制代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. using namespace std;
  5. const int N = 5000010;
  6. int arr[N];
  7. int main()
  8. {
  9.     int n, k;
  10.     cin >> n >> k;
  11.     for (int i = 0; i < n; i++)
  12.     {
  13.         scanf("%d", &arr[i]);
  14.     }
  15.     sort(arr, arr + n);
  16.     cout << arr[k] << endl;
  17.    
  18.     return 0;
  19. }
复制代码

这两个案例中,输⼊的数据量都⽐较⼤,在输⼊数据的时候如果使⽤ cin ,都会出现超时的问题,但是换成是 scanf 的⽅式就能正确的通过。这就是因为两者性能上的差异导致的。

  • C++中为了⽀持混淆使⽤ cin/cout 和 scanf/printf ,C++标准库默认会将 cin 、 cout等C++流对象与 stdin 、 stdout 等C标准库的流对象同步在⼀起。这种同步操作意味着每次使⽤ cin 或 cout 时,都会⾃动刷新C标准库的缓冲区,以确保C++和C的I/O是⼀致的。这就导致了性能的降落。
  • 在默认情况下, cin 和 cout 之间存在⼀种绑定关系。这种绑定意味着,每当从 cin 读取数据时,任何之前通过 cout 输出的内容都会被逼迫刷新到屏幕上。这种绑定也可能导致性能问题,特殊是在必要频仍读取⼤量数据的情况下。
优化⽅案和演⽰

  1. #include<iostream>  
  2. #include<ctime>  
  3. #include<cstdio>  
  4. using namespace std;  
  5. const int num = 10000000;  
  6. int main()  
  7. {  
  8.         int i, x;  
  9.         //freopen是将stdin重定向到⽂件  
  10.         //意思是scanf可以⽂件中读取数据  
  11.         freopen("data.txt", "r", stdin);  
  12.         clock_t t1, t2;  
  13.         t1 = clock();  
  14.         for (i = 0; i < num; i++)
  15.         {  
  16.                 scanf("%d", &x);  
  17.         }  
  18.         t2 = clock();  
  19.         cout << "Runtime of scanf: " << t2 - t1 << " ms" << endl;  
  20.        
  21.         return 0;  
  22. }
复制代码

  1. #include<iostream>  
  2. #include<ctime>  
  3. #include<cstdio>  
  4. using namespace std;  
  5. const int num = 10000000;  
  6. int main()  
  7. {  
  8.         //freopen是将stdin重定向到⽂件  
  9.         //意思是cin可以⽂件中读取数据  
  10.         freopen("data.txt", "r", stdin);  
  11.         int i, x;  
  12.         clock_t t1, t2;  
  13.         t1 = clock();  
  14.         for (i = 0; i < num; i++)
  15.         {  
  16.                 cin >> x;  
  17.         }  
  18.         t2 = clock();  
  19.         cout << "Runtime of cin: " << t2 - t1 << " ms" << endl;  
  20.         return 0;  
  21. }
复制代码

  1. #include<iostream>  
  2. #include<ctime>  
  3. #include<cstdio>  
  4. using namespace std;  
  5. const int num = 10000000;  
  6. int main()  
  7. {  
  8.         ios::sync_with_stdio(false); //取消给C语⾔输⼊输出缓冲区的同步  
  9.         cin.tie(0); //取消了cin和cout的绑定  
  10.        
  11.         freopen("data.txt", "r", stdin);  
  12.         int i, x;  
  13.         clock_t t1, t2;  
  14.         t1 = clock();  
  15.         for (i = 0; i < num; i++)  
  16.         {  
  17.                 cin >> x;  
  18.         }  
  19.         t2 = clock();  
  20.         cout << "Runtime of cin: " << t2 - t1 << " ms" << endl;
  21.          
  22.         return 0;
  23. }
复制代码

所以未来我们在使⽤ scanf / printf 和 cin / cout 决定的时候,如果要追求性能那就使⽤scanf / printf ,或者优化版的 cin / cout ,如果不追求性能,直接使⽤ cin / cout 就⾏。


  • 如果输⼊的数据量⽐较⼩( 10^6 以内)的话,⽤ cin 和 cout 或 scanf 和printf 都⾏;
  • 但是输⼊的数据量⽐较⼤( 10^9 左右)的话,更推荐使⽤ scanf 和 printf ,制止因为输⼊输出的开销,导致代码超时;
  • 在⼤多数场景下 printf / scanf 和 cin / cout 的使⽤根据个⼈风俗进⾏选择即可。
cin/cout性能问题讨论和优化方法


  • 在 C++ 中,标准输入输出流如 cin 和 cout 是由 C++ 的标准库提供的;而在 C 语言中,标准输入输出函数如 scanf 和 printf 是由 C 标准库提供的。由于 C++ 是从 C 发展而来的语言,C++ 标准库的输入输出流系统必要与 C 标准库的输入输出系统兼容,以确保在同一程序中能够混淆使用 C 和 C++ 的输入输出函数。为了实现这种兼容性,C++ 标准库默认会将cin、cout 等 C++ 流对象与 stdin、stdout 等 C 标准库的流对象同步在一起。这种同步操作意味着每次使用 cin 或 cout 时,都会自动刷新 C 标准库的缓冲区,以确保 C++ 和 C 的 I/O 是同等的。
  • 在默认情况下,cin 和 cout 之间存在一种绑定关系。这种绑定意味着,每当从 cin 读取数据时,任何之前通过 cout 输出的内容都会被逼迫刷新到屏幕上。这个机制保证了输出内容能够立即显示给用户,这对于交互式程序非常有用。但是,这种绑定也可能导致性能问题,特殊是在必要频仍读取大量数据的情况下。这是因为每次从 cin 读取数据都会触发一次输出缓冲区的刷新,纵然实际上没有进行输出操作,也会浪费时间。
ios::sync_with_stdio(false)

作用

调用 ios::sync_with_stdio(false) 可以关闭 C++ 标准库与 C 标准库之间的 I/O 同步。这意味着:


  • C++ 标准库的 cin 和 cout 将不再与 C 的 stdin 和 stdout 同步。
  • cin 和 cout 的 I/O 操作将不再自动刷新 C 标准库的缓冲区,这减少了不必要的同步开销,从而提高了 I/O 操作的服从。
原理

默认情况下,ios::sync_with_stdio(true) 会使 cin、cout 等流对象与 stdin、stdout 等流对象同步。这种同步操作会在每次 I/O 操作时确保两者之间的数据同等性,但也会增加额外的性能开销。
当你调用 ios::sync_with_stdio(false) 时,C++ 标准库会排除这种同步,从而允许 cin 和 cout 的 I/O 操作以更高的服从独立进行。这样做的长处是,如果你的程序只使用 C++ 标准库的 I/O 操作(比方使用 cin 和 cout),你可以获得更快的实行速度。
使用场景



  • 竞赛编程:在处理大量输入输出的竞赛环境中,这种优化非常常见,因为它可以明显减少 I/O 操作的时间。
  • 只使用 C++ I/O:如果你的程序只使用 cin、cout 进行 I/O,而不涉及 C 的 I/O 函数,那么可以安全地使用这项优化来提高性能。
留意事项



  • 混用 C 和 C++ I/O 函数:如果你的程序既使用了 C 的 I/O 函数(如 printf、scanf),又使用了 C++ 的 I/O 函数(如 cin、cout),则不建议使用 sync_with_stdio(false),因为这可能导致不可预期的举动,比方输出次序错乱。
  • 线程安全性:排除同步后,I/O 操作可能不再是线程安全的,特殊是在多线程环境中必要谨慎使用。
cin.tie(0)

cin.tie(0) 是C++中用于排除标准输入流 cin 与标准输出流 cout 之间默认绑定的一个方法。在C++中,cin 是istream类型的流对象, cout 是ostream 类型的流对象,分别用于标准输入和标准输出。
作用

cin.tie(0) 的作用是取消 cin 与 cout 之间的绑定。这样一来,当从 cin 读取数据时,cout 的缓冲区就不会被刷新。这可以提高输入操作的速度,尤其是在必要处理大量数据的情况下。
原理

在默认情况下,cin 和 cout 之间存在一种绑定关系。这种绑定意味着,每当从 cin 读取数据时,任何之前通过 cout 输出的内容都会被逼迫刷新到屏幕上。这个机制保证了输出内容能够立即显示给用户,这对于交互式程序非常有用。但是,这种绑定也可能导致性能问题,特殊是在必要频仍读取大量数据的情况下。这是因为每次从 cin 读取数据都会触发一次输出缓冲区的刷新,纵然实际上没有进行输出操作,也会浪费时间。
使用场景

cin.tie(0) 主要适用于以下几种情况:

  • 高性能输入输出:

    • 在算法竞赛或必要高速输入输出的程序中,排除 cin 和 cout 的绑定可以明显提升程序的运行速度,尤其是在处理大量数据时。

  • 非交互式程序:
    2. 如果程序不是交互式的,或者输出不必要实时显示给用户,那么排除绑定可以制止不必要的缓冲区刷新。
  • 并行处理:
    3. 当程序必要同时处理多个输入输出流时,排除绑定有助于减少同步带来的耽误。
留意事项

虽然 cin.tie(0) 可以提高程序的性能,但也必要留意以下几点:


  • 程序逻辑:在某些依赖于默认绑定举动的程序中,取消绑定可能会导致程序逻辑错误。比方,如果期望在读取输入前能看到提示信息,则必要显式地调用 cout 的 flush 方法确保输出被刷新。
  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.     ios::sync_with_stdio(false);       // 取消C风格I/O的同步
  6.     cin.tie(0);                        // 解除cin与cout的绑定
  7.     int number;
  8.     cout << "请输入一个数字: ";
  9.     cin >> number;
  10.     cout << "您输入的数字是: " << number << endl;
  11.     return 0;
  12. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表