【2024最新】C++读写优化超详细解析(cin优化+普通快读+fread)_输入输出优化_快读快写_算法竞赛

在算法竞赛中,读入速度和输出速度一直是卡常的重要手段。也有不少人经历过被题目卡 cin 的情况。今天我给大家介绍一下算法竞赛中常用的读写方法及其优化。

声明:大部分情况下,只用读入优化就行。对于输出量大的题目再考虑使用输出优化。

一、scanf/printf

这两个函数来源于传统的 C,在 <stdio.h><cstdio>(仅 C++)中。使用方法:scanf("%占位符",&var); printf("%占位符\n",var);。这样比传统的 cin/cout 快,但由于书写复杂而很少被人采用。

scanf/printf 用法参考文章:详解c++中scanf和printf用法

二、cin/cout 优化

cin 和 cout是 C++ 的标准输入输出流,在 <iostream> 头文件中,使用方法也十分简单:cin>>var; cout<<var<<endl; 所以深受人们的喜爱。
在时间要求不高的题目中,用它们既省事,又可以让代码更美观。

缺点:cin/cout 在不加优化的情况下速度慢于 scanf 和 printf。

原因:C++ 为了和 C 保持同步、在混用 printf&scanf 和 cin&cout时的时候不发生混乱,将它的输入/输出流绑到了一起。

解决方案:可以手动关闭同步,从而提高 cin 和 cout 的效率。std::ios::sync_with_stdio(false); 同时,还可以通过std::cin.tie(nullptr); 来解除 cin 和 cout之间的绑定,进一步减轻 cin 的负担。

cin/cout 用法:C++ 基础的输入输出介绍:掌握cin与cout的奥秘

三、endl 优化

有一个被人忽略的“大杀手”:endl。这一个语句和 \n 的效果相同,但更方便书写,因此被人们广泛采用。其实它的速度也特别慢。可能会导致某些题目超时。

原因:endl 输出时会清空缓冲区,这是为了让用户能及时看到输出,但会拖慢速度。并且由于它本身的功能定义,很难进行优化。

解决方案:打不过就不用呗 对于输出量大且需要换行的题目,使用 endl 有超时的风险,建议使用 cout<<'\n'。(平常刷题也建议用 \n,比较保险)

在实测中,C++14 的版本下,cin/cout 优化 + endl 优化的速度已经远快于 scanf/printf,建议在新评测机上使用上面两种方法优化

#include<iostream>
using namespace std;
int a[105];
int main(){
   
   
	ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
   
   
	    cin>>a[i];
	}
	for(int i=1;i<=n;i++){
   
   
		cout<<"a["<<i<<"]="<<a[i]<<"\n";
	}
    return 0;
}

四、传统快读、快写

原理:单个字符的输入输出速度要比读入数字快,因此我们以字符的形式先读入,然后处理计算转为数字,再用字符输出。

关于 isdigit()

在判断某个字符是不是整数时用的 isdigit() 函数,在不同编译器上的速度不一样。

这篇文章 中的测试结果:自己写比 VS 中的 isdigit() 快,但比 g++ 中的 isdigit() 慢。而且 g++ 中的 isdigit() 比 VS 中的 isdigit() 更快。

这篇文章 给我们展示了 Linux 内核中该函数王者级别的实现,大家可以学习。

自己写的话:

#define my_isdigit(c) ( (c)>='0'&&(c)<='9' ) // C语言
inline bool my_isdigit(char c){
   
    return (c>='0'&&c<='9'); } // C++

快读

原理是先用单个字符读入所有零散的数字,再拼起来。拼数和判断字符见 这篇文章

template<typename T>
inline void read(T &x){
   
   
	T w=1; x=0; 
	char c=getchar(); 
	while(!isdigit(c)){
   
    if(c=='-'){
   
   w=-1;} c=getchar();}  
	while(isdigit(c)){
   
    x=x*10+(c-'0'); c=getchar();} 
	x=x*w;
}

快写

原理是把原来完整的数字拆成一个个字符输出。用递归的常数会略大,可以用模拟栈的方法时限。

递归代码:

template<typename T>
inline void write(T x){
   
   
    if(x<0){
   
    putchar('-'); x=-x;}
    if(x>=10){
   
    write(x/10);}
    write(x%10+'0'); //+'0'是为了让数字类型的x%10变成字符输出
}

模拟栈代码:(不能用模板了,要自己指定类型)

inline void write(int x){
   
   
    static int st[35] = {
   
   0}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值