【程序设计竞赛】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();
        // Java
        System.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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/385216.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java程序设计】【C00251】基于Springboot的医院信息管理系统(有论文)

基于Springboot的医院信息管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的医院信管系统 本系统分为管理员功能模块、系统功能模块以及医生功能模块。 系统功能模块&#xff1a;医院信管系统&#xff0c;…

Swift Combine 用 Future 来封装异步请求 从入门到精通十一

Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三Swift Combine 发布者publisher的生命周期 从入门到精通四Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五Swift Com…

【C语言】解析刘谦春晚魔术《守岁共此时》

今年的春晚上刘谦表演了魔术《守岁共此时》&#xff0c;台上台下积极互动&#xff08;尤其是小尼&#xff09;&#xff0c;十分的有趣。刘谦老师的魔术不仅仅是他的高超手法&#xff0c;还有这背后的严谨逻辑&#xff0c;下面我们来用C语言来解析魔术吧。 源代码 #define _CRT…

[Python] 文件

这篇是Python基础语法的一个结尾了&#xff0c;还是可莉跟着大家一起学习哦~ 可莉将这篇博客收录在&#xff1a;《Python》 可莉推荐的优质博主主页&#xff1a;Keven ’ s blog 目录 一、文件是什么 二、常用的文件操作函数 1、打开文件 2、关闭文件 3、读取文件 read( ) …

JAVA设计模式之命令模式详解

命令模式 1 命令模式介绍 命令模式(command pattern)的定义: 命令模式将请求&#xff08;命令&#xff09;封装为一个对象&#xff0c;这样可以使用不同的请求参数化其他对象&#xff08;将不同请求依赖注入到其他对象并且能够支持请求&#xff08;命令&#xff09;的排队执行…

jsp课程教学管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 课程教学管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

vue3-内置组件-Suspense

Suspense (实验性功能) <Suspense> 是一项实验性功能。它不一定会最终成为稳定功能&#xff0c;并且在稳定之前相关 API 也可能会发生变化。 <Suspense> 是一个内置组件&#xff0c;用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌…

最新Burp Suite入门讲解

Burp Suite的安装 Burp Suite是一款集成化的渗透测试工具&#xff0c;包含了很多功能&#xff0c;可以帮助我们高效地完成对Web应用程序的渗透测试和安全检测。 Burp Suite由Java语言编写&#xff0c;Java自身的跨平台性使我们能更方便地学习和使用这款软件。不像其他自动化测…

Offer必备算法06_位运算_十道力扣OJ题详解_由易到难

目录 位运算算法原理 ①力扣191. 位1的个数 解析代码 ②力扣338. 比特位计数 解析代码 ③力扣461. 汉明距离 解析代码 ④力扣136. 只出现一次的数字 解析代码 ⑤力扣260. 只出现一次的数字 III 解析代码 ⑥力扣面试题 01.01. 判定字符是否唯一 解析代码 ⑦力扣26…

STM32F1 - GPIO外设

GPIO 1> 硬件框图2> 工作模式 1> 硬件框图 2> 工作模式 C语言描述 /** * brief Configuration Mode enumeration */typedef enum { GPIO_Mode_AIN 0x0, // Analog Input 模拟输入 GPIO_Mode_IN_FLOATING 0x04, // input floating 浮空输入GPIO_Mode_I…

Linux第47步_安装支持linux的第三方库和mkimage工具

安装支持linux的第三方库和mkimage工具&#xff0c;做好移植前的准备工作。 编译linux内核之前&#xff0c;需要先在 ubuntu上安装“lzop库”和“libssl-dev库”&#xff0c;否则内核编译会失败。 mkimage工具会在zImage镜像文件的前面添加0x40个字节的头部信息,就可以得到uI…

【JAVA WEB】JavaScript--函数 作用域 对象

目录 函数 语法格式 示例 定义没有参数列表&#xff0c;也没有返回值的一个函数 定义一个有参数列表 &#xff0c;有返回值的函数 关于参数个数 函数表达式 作用域 作用域链 对象 基本概念 创建对象 1.使用 字面量 创建对象 2.使用new Object()创建对象 3.使…

Microsoft Word 超链接

Microsoft Word 超链接 1. 取消超链接2. 自动超链接2.1. 选项2.2. 校对 -> 自动更正选项2.3. Internet 及网络路径替换为超链接 References 1. 取消超链接 Ctrl A -> Ctrl Shift F9 2. 自动超链接 2.1. 选项 2.2. 校对 -> 自动更正选项 ​​​ 2.3. Internet…

java中事务的使用

文章目录 前言一、同一张表1.业务代码2.测试代码3.测试结果 二、不同表1.业务代码2.测试代码3.测试结果 总结 前言 本文将介绍在springboot中使用Transactional注解来完成对数据库事务的操作&#xff0c;保证数据一致性。 一、同一张表 1.业务代码 Controller Controller p…

二、ClickHouse简介

ClickHouse简介 前言一、行式存储二、DBMS功能三、多样化引擎四、高吞吐写入能力五、数据分区与线程级并行六、场景七、特定版本 前言 ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的列式存储数据库&#xff08;DBMS&#xff09;&#xff0c;使用 C 语言编写&#xff0c;主要…

C++线程浅谈

本篇文章我们来介绍一下C 多进程 多线程的技术 1.为什要学习多线程 多进程 提高程序的性能&#xff1a;进程和线程可以使程序并发执行&#xff0c;从而充分利用计算机的多核处理器和资源&#xff0c;提高程序的执行效率和吞吐量。 实现复杂任务&#xff1a;通过将任务划分为多…

Acwing---842.排列数字

排列数字 1.题目2.基本思想3.代码实现 1.题目 给定一个整数 n&#xff0c;将数字 1∼n排成一排&#xff0c;将会有很多种排列方法。 现在&#xff0c;请你按照字典序将所有的排列方法输出。 输入格式 共一行&#xff0c;包含一个整数 n。 输出格式 按字典序输出所有排列方案…

Java安全 URLDNS链分析

Java安全 URLDNS链分析 什么是URLDNS链URLDNS链分析调用链路HashMap类分析URL类分析 exp编写思路整理初步expexp改进最终exp 什么是URLDNS链 URLDNS链是Java安全中比较简单的一条利用链&#xff0c;无需使用任何第三方库&#xff0c;全依靠Java内置的一些类实现&#xff0c;但…

读千脑智能笔记12_阻止人类灭绝

1. 阻止人类灭绝 1.1. 宇宙中唯一知道这些的物体&#xff0c;唯一知道宇宙存在的物体&#xff0c;是我们的大脑 1.2. 如果没有关于某个事物的知识&#xff0c;我们能说这个事物就一定存在吗&#xff1f; 1.2.1. 我们的大脑扮演着这样一个独特的角色&#xff0c;这很令人着迷…

使用matplotlib库在Python中绘制散点图

使用matplotlib库在Python中绘制散点图&#xff0c;展示了两个月份的气温变化。 # coding: utf-8 from matplotlib import pyplot as plt # 导入matplotlib库中的pyplot模块&#xff0c;并重命名为plt from matplotlib import font_manager # 导入font_manager模块&#xff…