当前位置: 首页 > news >正文

【程序设计竞赛】C++与Java的细节优化

必须强调下,以下的任意一种优化,都应该是在本身采用的算法没有任何问题情况下的“锦上添花”,而不是“雪中送炭”。
如果下面的说法存在误导,请专业大佬评论指正

读写优化

C++读写优化——解除流绑定

在ACM里,经常出现数据集超大造成 cin TLE的情况,其实cin效率之所以低,不是比C低级,而是因为需要与scanf的缓冲区同步,导致效率降低,而且是C++为了兼容C而采取的保守措施。
C++代码中添加 ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);这一段之后,读取速度即可无限趋近于scanfprintf
如果代码首部没有using namespace std; 则要换成std::ios::sync_with_stdio(0),std::cin.tie(0),std::cout.tie(0);

#include <bits/stdc++.h>
using namespace std;int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);// 未使用using namespace std;时使用下方写法// std::ios::sync_with_stdio(0),std::cin.tie(0),std::cout.tie(0);// 代码主体读取、操作、打印
}

std::ios::sync_with_stdio(0)

在 C++ 中,取消同步流(std::ios::sync_with_stdio)是一个常用的技巧,用来加快输入/输出流(I/O)的速度。默认情况下,C++ 的标准库(iostream)与 C 的标准库(stdio)之间是同步的,这意味着它们共享缓冲区,并且每次使用其中一个库的 I/O 功能时,都会刷新另一个库的缓冲区。这保证了数据的一致性,但也增加了性能开销。

通过调用 std::ios::sync_with_stdio(0),你可以取消这种同步,这通常会导致 I/O 操作的速度显著提高。但是,一旦取消了同步,就不能再混用 C++ 和 C 的 I/O 函数(如 cin/cout 和 scanf/printf),因为这可能会导致输出顺序不确定或其他问题。

如果已经采用了C++的输入函数cin,就避免再使用C的scanf;同样的如果已经使用 cout 就避免再使用 printf

cin.tie(0)

在默认的情况下cin绑定的是cout,每次执行的时候都要调用flush,这样会增加IO负担。
这行代码解除了 cin(输入流)与 cout(输出流)之间的绑定。默认情况下,cin 与 cout 绑定在一起,这意味着在每次从 cin 读取之前,cout 的缓冲区都会被自动刷新。通过解除绑定,可以进一步提高 I/O 性能,但这也意味着在输出和输入操作之间不再自动刷新 cout 的缓冲区。

cout.tie(0)

这行代码通常不是必须的,因为 cout 默认情况下并不绑定到其他流。它的主要作用是确保 cout 不与任何其他流(例如 cin 或 cerr)绑定。但在大多数情况下,这行代码并不会改变默认行为。

C++换行输出

endl会输出’\n’(\n是转义字符,代表换行),然后立即刷新缓冲区并输出到屏幕上。由于要刷新缓冲区,endl会比\n慢一点,一般不建议使用。以下是endl实现:

template <class _CharT, class _Traits>
inline _LIBCPP_INLINE_VISIBILITY
basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os)
{__os.put(__os.widen('\n'));__os.flush();return __os;
}

C++中换行大多喜欢写 cout << endl;,然而据acmer和本人赛场亲身经历,这种写法比 cout << '\n; 输出速度要慢许多。当然这不乏出题人的原因,不过为了避免悲剧的发生希望大家还是使用如下两种方法。

  1. 在代码头部使用宏定义#define endl '\n' 替换endl
  2. 改掉使用endl的习惯
#include <bits/stdc++.h>
#define endl '\n'int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);// 上方使用了宏定义,代码编译预处理阶段就将endl换成了'\n'cout << endl;// 直接输出'\n'cout << '\n';
}

C/C++自定义快读快写

本人没有亲自使用过,不过是看别人代码中有如此运用。据说C++17后getchar()/putchar()已经被负优化了,未知真假,个人选择使用。

inline int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
}inline void write(int x)
{char F[200];int tmp=x>0?x:-x;if(x<0)putchar('-');int cnt=0;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);
}

Java快读快写

大部分初学Java的人应该是使用如下代码进行Java的读写,不过下面这个代码的读写,在面对大量数据的情况下是比较慢的。

import java.util.Scanner;public class Main {public static void main(String[] args) {// java.util 包下的读取Scanner sc = new Scanner(System.in);int n = sc.nextInt();// JavaSystem.out.println(n);sc.close();}
}

下方的读写代码速度较快,经过实践检验,建议采用。该部分代码经过真实调试,应该是不存在什么问题。
特别提醒!!!如果使用了下方代码中的快速输出,代码最后必须使用out.flush(); 必须使用out.flush(); 必须使用out.flush();

快速读入的代码按需使用,写代码时不一定要全部写,如果在XCPC赛场上使用Java,可以提前写好该模板。

import java.io.*;/*** 自定义快读类*/
class Scanner {static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));// 字符串快速读入对象static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));public int nextInt() {try {st.nextToken();return (int) st.nval;} catch (IOException e) {throw new RuntimeException(e);}}public double nextDouble() {try {st.nextToken();} catch (IOException e) {throw new RuntimeException(e);}return st.nval;}public float nextFloat() {try {st.nextToken();} catch (IOException e) {throw new RuntimeException(e);}return (float) st.nval;}public long nextLong() {try {st.nextToken();} catch (IOException e) {throw new RuntimeException(e);}return (long) st.nval;}public String next() {try {st.nextToken();} catch (IOException e) {throw new RuntimeException(e);}return st.sval;}// 按行读入字符串public String readLine() {String s = null;try {s = br.readLine();} catch (IOException e) {e.printStackTrace();}return s;}
}
public class Main {// 快速输出对象static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));public static void main(String[] args) {// 创建自定义的Scanner类Scanner sc = new Scanner();/*** 快读使用案例*/int n = sc.nextInt();double d = sc.nextDouble();float f = sc.nextFloat();// 读入字符串(以空格、回车结尾)String str = sc.next();// 整行读入字符串(以回车换行结尾)String line = sc.readLine();/*** 快速输出使用案例*/out.println(n);out.println(d);out.println(f);out.println(str);out.println(line);// 快速输出必须要刷新缓冲区,否则无法输出out.flush();}
}

读写样例
在这里插入图片描述

其他玄学优化——自行试用

下方玄学,只是部分传言,有些优化的效果似乎并不显著;有时不妨一试。

常用函数优化

inline int abs(int x)
{int y=x>>31;return (x+y)^y;
}
inline int max(int x,int y)
{int m=(x-y)>>31;return (y&m)|(x&~m);
}
inline int min(int x,int y)
{int m=(x-y)>>31;return (y&m|x&~m)^(x^y);
}
inline void swap(int &x,int &y)
{x^=y,y^=x,x^=y;
}
inline int ave(int x,int y)
{return (x&y)+((x^y)>>1);
}

变量自增

++i快于i++

用减法代替取模运算

把函数中的循环变量在整个函数开头用register统一定义好

频繁使用的数用register,和inline一个用法,只不过有可能把变量存入CPU寄存器,来减少时间;某些生命周期不重叠的变量合并,减少创建变量空间的时间。

int main()
{register int i;for (i = 1; i <= n; ++i){// 逻辑部分}for (i = 1; i <= n; ++i){// 逻辑部分}/*下方循环多次使用i*/
}

减少使用STL,他们的常数特别大

现在大部分OJ平台都会自动开O2优化,所以可能STL常数问题可能也没那么严重,有时候也可以尝试手动开O2优化。据说有些时候可能会出现stl的map反而比自己手写map还快的情况…所以自己看情况吧

// 代码头部预处理指令手动打开O2
#pragma GCC optimize(2)

define比赋值更快

定义数组大小时尽量用奇数

尽量不要用bool,int型比bool快

if()else() 语句比三元运算符慢;但if语句比三元运算符快

学会合理使用位运算

  • 判奇偶性:n&1相当于n%2==1。
  • 交换变量x与y:
inline void swap(int &x,int &y)
{x^=y^=x^=y;
}

相关文章:

  • ch3-homework-基于InternLM和LangChain搭建自己的知识库
  • MySQL:常用指令
  • 物联网技术的崛起:驱动智慧景区的新篇章
  • 麻将普通胡牌算法(带混)
  • 【5G NR】【一文读懂系列】移动通讯中使用的信道编解码技术-Turbo编码原理
  • 【51单片机】直流电机实验和步进电机实验
  • 六、Datax通过json字符串运行
  • 阅读《极客时间 | Kafka核心技术与实战》(一)【Kafka入门】
  • CDN直播基础概念与优化思路
  • 什么是系统工程(字幕)28
  • 【Spring MVC篇】返回响应
  • 全栈笔记_插件篇(谷歌扩展插件开发系列之 manifest.json配置文件)
  • Python学习之路-爬虫提高:selenium
  • 【蓝桥杯单片机入门记录】认识单片机
  • linux系统下vscode portable版本的python环境搭建003:venv
  • Brief introduction of how to 'Call, Apply and Bind'
  • github指令
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • HTTP那些事
  • java正则表式的使用
  • Less 日常用法
  • opencv python Meanshift 和 Camshift
  • TCP拥塞控制
  • Vultr 教程目录
  • 编写符合Python风格的对象
  • 二维平面内的碰撞检测【一】
  • 分布式熔断降级平台aegis
  • 基于Vue2全家桶的移动端AppDEMO实现
  • 检测对象或数组
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 区块链共识机制优缺点对比都是什么
  • 什么软件可以剪辑音乐?
  • 无服务器化是企业 IT 架构的未来吗?
  • #etcd#安装时出错
  • %3cli%3e连接html页面,html+canvas实现屏幕截取
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (13)[Xamarin.Android] 不同分辨率下的图片使用概论
  • (145)光线追踪距离场柔和阴影
  • (SpringBoot)第二章:Spring创建和使用
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • .NET Core 中的路径问题
  • .net实现客户区延伸至至非客户区
  • @test注解_Spring 自定义注解你了解过吗?
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛
  • [14]内置对象
  • [2009][note]构成理想导体超材料的有源THz欺骗表面等离子激元开关——
  • [AIGC] MySQL存储引擎详解
  • [Angularjs]ng-select和ng-options
  • [C#]winform部署yolov9的onnx模型
  • [HNOI2018]排列
  • [iphone-cocos2d]关于Loading的若干处理和讨论
  • [JS入门到进阶] 7条关于 async await 的使用口诀,新学 async await?背10遍,以后要考!快收藏