百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

用 C++ 和 Java 写算法,有差别吗?

bigegpt 2024-10-16 07:50 2 浏览

来源|GitChat精品课

编辑|猿姐


PS:下文中,上面的代码是 C++ 的实现方式,下面的是 Java 的实现方式。C++ 语法使用的是 C++11之后的版本,Java 使用的是 Java6 之后的版本。

1、C++ 和 Java 语法特性的相似性

同为 C 语言家族的 Java 和 C++ 语言层面的相似性是有客观基础的。我通常这样理解:Java 是跨平台的 C++,是一种更好的 C++(是不是有点拉仇恨的感觉)。

2、基本数据类型

C++ 的基本数据类型有:int、unsigned int、long、unsigned long、short、unsigned short、char、unsigned char、bool、float 和 double;

相应的,Java 也有 8 种基本数据类型,分别是:byte、short、int、long、float、double、char 和 boolean。

大部分情况下,两种语言的基本数据类型可以根据下表进行一对一的转换,但是也有差异,需要特别注意。

首先是 char,C++ 的 char 是 8 比特无符号整数,顺便表示了 ASCII 字符;Java 的 char 是 16 比特,天生就可以表示宽字符集的字符。

另一个需要注意的是 long 类型,C++ 的 long 是不可移植类型,在不同的系统上其长度不一样,可能是 32 位,也可能是 64 位,所以 C++ 程序员应尽量避免使用 long。

Java 的 long 比较单纯,无论是 32 位的系统还是 64 位的系统,它都表示 64 位整数。


反过来,Java 会用 d 或 D 表示一个直接数字是 double 类型的浮点数,比如 200.0d 或(200.0D),但是 C++ 不支持,因为 C++ 默认一个浮点型的直接数字就是 double 类型。

C++ 用字面量符号 f 或 F 表示一个直接数字是 float 类型浮点数,比如 250.1 f(或 250.1F),这一点 Java 也是一样的。

C++ 用字面量符号 l 或 L 表示 long,用 UL 表示 unsigned long。

3、字符串

很多 C++ 程序员喜欢的用 char* 或 char 类型的数组存储字符串,这其实是 C 语言用户带过来的习惯,我给出的 C++ 算法实现对字符串一般都用 std::string,对应 Java 的 String。

std::string 和 String 的用法对照如下表所示:



4、基本语法

虽然 Java 的语法和 C++ 十分地相似,但是语言层面还有一些不同。C++ 允许全局函数的存在,Java 则不允许,不过 Java 也留了个口子,就是用静态成员函数。Java 没有指针,对象的传递和返回都是用的引用的方式,并且不需要像 C++ 那样用 “&” 做特殊的语法标记。

大多数介绍 Java 的书籍开篇就是类和抽象,然后才是基本的语法,这和 Java 上等人的气质是一致的,连这都不会,咋做程序员?C++ 应该多提升一下气质,少用点指针和全局函数。本文为了对比 C++ 和 Java 的相似性,所以就从基本语法结构开始介绍。

运算符和赋值

二者的运算符几乎一样,甚至 “++” 和 “—” 运算符都一样有前缀式和后缀式两种形式,意义也一样;运算符的优先级规则也是一样的。赋值语句两者基本上是一样的,看看每一行结尾的 “;” 你就知道它们有多相似。

条件判断与循环

条件判断方面,C++ 与 Java 的 if 语句、switch 语句用法都相同;逻辑表达式的结构和语法、逻辑运算符的优先级也都相同。

C++ 的三种基本循环方式是 while 循环、do…while 循环和 for 循环,Java 都支持,甚至连关键字和 break、continue 控制语句的意义也一样。

C++11 版本引入了一种根据范围循环的语法,一般理解和 Java 的增强 for 循环类似,比如这种 C++ 循环形式:


Java 与之对应的形式是:


C++ 的基于范围的 for 循环也可用于 C++ 的标准库对象,用于取代老旧的迭代器循环方式:


同样,Java 的增强 for 循环也支持基于 Collection 的遍历,理解起来不成问题:


传统的 C++ 语言是用迭代器对标准库的容器进行遍历,比如:


C++ 的容器都有 begin() 和 end() 接口,分别得到起始位置的迭代器的值和结束位置的迭代器的值,很多标准库的算法都会用到迭代器。

C++ 用当前迭代器的值是否等于 end() 代表的结束位置迭代器的值来判断是否遍历结束。

Java 的 Collection 也有迭代器的机制,Java 用 hasNext() 判断是否遍历结束。

C++ 直接用 “ * ” 提领迭代器,得到对象本身的引用,Java 用迭代器的 next() 接口得到对象本身的引用。以上 C++ 代码可以翻译成如下 Java 代码:


除了以上的 for 循环语句,C++ 还支持 for_each() 形式的遍历 + 处理操作,也是配合迭代器使用,for_each() 的前两个参数是一对迭代器,代表循环的起始位置和结束位置。

第三个参数是一个可调用对象,即函数对象(C++11 版本之后,这个参数还可以是一个 Lambda 表达式),举个栗子:


Java 没有与之对应的泛型函数接口,但是 Java 的很多 Collection 都支持 forEach() 接口:


C++ 的 for_each()其实用起来并不好用,自从 C++11 之后,除了怀旧派 C++ 程序员,其他人应该很少会再用 for_each() 了,基于范围的 for 循环简直丝滑的不要不要的。

5、函数

C++ 的函数结构和 Java 也一样,函数调用的形参和实参对应方式也一样,也无需多做说明。

6、数组

C++ 和 Java 都支持原生数组,并且数组索引都是从 0 开始。C++ 中定义数组的同时就分配了存储空间,所以在定义时要指定长度,使用 new 动态申请内存时,要指定长度。

但是一种情况除外,那就是静态初始化数组的形式,因为此时编译器知道需要多少空间存储这些数据,如下是 C++ 定义数组的常用形式:


Java 如果仅仅是声明一个数组,可以不指定长度,因为此时并不分配存储空间,需要分配空间的时候,用 new。与之对应的 Java 语言的形式是:


C++ 中二维数组的每一维长度必须相同,因为 C++ 的二维数组实际上只是一块连续的存储空间而已,甚至可以用一维数组的下标遍历全部二维数组的存储空间。

Java 没这要求,因为 Java 的每一维都是可以单独申请存储空间的。但是二者在使用形式上是一样的。C++ 定义和初始化二维数组一般有这几种形式:


与之对应的 Java 语言初始化二维数组的形式是:


C++ 也支持动态内存形式的二维数组,一般有两种使用方法,Java 都有与之对应的习惯用法:


与之对应的 Java 的方法是:


这代码相似度很高。C++ 代码最后要用 delete[] 手动释放为数组申请的内存,Java 是不需要的。

C++ 还可以利用二维数组在内存中是连续存储这一特性,使用时用下标计算将一维数组当成二维数组使用,计算的方法是:a\[i]\[j] = b[i * 2 + j],如下代码示例:


遇到这样的代码,需要根据上述对应关系,小心地理解算法代码的意图。一些棋盘类游戏通常喜欢用一维数组存储二维的逻辑棋盘结构,好在 Java 也可以这么做,转换起来也没什么难度。

7、类和封装

首先说说 C++ 的 struct,Java 没有与之对应的相似物的,但是完全可以用 class 来替换这个概念。为什么这么说呢?

因为在 C++ 中,struct 的位置有点尴尬,它是个 POD 吧,但它的成员又可以用非 POD 的数据类型,比如 std::string,甚至还可以定义虚接口,一旦有了这些东西,它就算不上 POD 了,除了成员默认是公有之外,和 class 没有太大差别。

在我看来,C++ 保留 struct 的主要意义是为了兼容旧的 C 或 C++ 的库,这些库中很多接口用到了 struct,其次是纯粹作为一种 POD 的 value type 来使用。

我的算法代码中也会用到 struct,大概是为了怀旧吧,其实完全可以用 class 代替,当然也可以很容易地翻译成 Java 的 class。来看个例子,对于这个 struct:


可以很轻松的转成 class:


自从 C++11 发布以后,我就觉得 C++ 和 Java 的 class 越来越像了,分开这么多年后,C++ 终于也支持 final 和 override 了。

从语法层面看,二者的差异很小,就小规模的算法而言,也很少会用到继承和重载之类的情况,所以,Java 程序员看懂 C++ 的 class 定义与实现一点都不难。

少有的一些差异,比如 C++ 的函数可以设置参数默认值,或者 C++ 的抽象机制采用的虚函数要使用 virtual 关键字等。先看一个典型的 C++ 类的定义与实现:


C++ 的类成员访问控制采用分节控制,用 public: 或 protected: 作为分节的标志,如果没有分节标志的类成员,则是默认的 private: 控制。

C++ 的成员函数可以有默认值,并且构造函数也支持默认值。以 Bucket 类为例,构造函数第二个参数默认值是 0,即在构造 Bucket 对象时,可以只确定一个参数 capicity,也可以在确定 capicity 参数的同时,确定 Bucket 的水量,比如:


Java 不支持参数默认值,但是可以通过重载函数解决这个问题,即增加一个只有 capicity 参数的构造函数:


C++ 没有抽象基类的语法,但是又抽象基类的概念,一般当一个类中有一个纯虚函数的时候,这个类是不能被直接实例化的,它就类似于是一个抽象基类,比如:


C++ 的函数有很多类型修饰,比如常见的 const,C++11 后新增了 final 和 override,但是 = 0 一直是一个比较奇怪的存在,它表明这个函数没有实现,需要在派生类中实现,同时,也说明这个类是不能被实例化的。

对于这样的机制,Java 可以理解为这就是个抽象基类:


C++ 的继承体系的语法与 Java 类似,只是语法形式上不同,Java 采用关键字:extends。

C++ 对于基类声明的虚函数,继承类中不需要再用 virtual 关键字修饰,当然,加了 virtual 关键字也没错误。Java 也一样,abstract 关键字再继承类中可以省去。

从 Shape 抽象类派生一个 Circle 类,C++ 的典型代码是:


Circle 构造函数后面的 :Shape(color),表示对基类的初始化,对于 Java 语言来说,相当于调用 super(color)。

以上代码翻译成 Java 语言,应该是这样的形式:


C++ 有时候也会将一个类声明为 final,意味着它不希望被其他类继承,从语法上做了限制,比如:


有时候,是某个不希望被派生类重载,比如:


这些对于 Java 程序员来说,并不陌生,语法上只是 final 关键字的位置不同,理解上应该不存在任何问题。


王老师此文一出,评论有亮点,摘选如下:

“不知道你写游戏算法不?特别是核心模块要是说语法 所有结构化 语言都殊途同归 但是用c和用java 在游戏算法 或者 广告类大数据运算上 怕不是一个层级”

“语法差不多,差别在性能,JAVA的优势在于开发容易,在高性能硬件上做服务也许感觉不到性能的损失,但不代表不损失,如果用c/c++做良好的实现的话,性能(吞吐量,并发量)必然提升一个档次,只做过JAVA的人是体会不到的”

相关推荐

【机器学习】数据挖掘神器LightGBM详解(附代码)

来源:机器学习初学者本文约11000字,建议阅读20分钟本文为你介绍数据挖掘神器LightGBM。LightGBM是微软开发的boosting集成模型,和XGBoost一样是对GBDT...

3分钟,用DeepSeek全自动生成语音计算器,还带括号表达式!

最近,大家慢慢了解到了DeepSeek的强大功能,特别是它在编程领域也同样强大。编程零基础小白,一行代码不用写,也能全自动生成一个完整的、可运行的软件来!很多程序员一直不相信小白不写代码也能编软件!下...

python学习笔记 3.表达式

在Python中,表达式是由值、变量和运算符组成的组合。以下是一些常见的Python表达式:算术表达式:由数值和算术运算符组成的表达式,如加减乘除等。例如:5+3、7*2、10/3等。字符...

5.7 VS 8.x,为什么用户不升级MySql

一般来说为了更好的功能和性能,都需要将软件升级到最新的版本,然而在开源软件中,由于一些开发商变化或其他的问题(开源授权变化),致使人们不愿使用最新的版本,一个最典型的问题就是CentOS操作系统。还有...

大厂高频:讲一下MySQL主从复制

大家经常听说主从复制,那么主从复制的意义?能解决的问题有哪些?主从复制能解决的问题就是在我们平时开发的程序中操作数据库的时候,大多数的情况查询的操作大大超过了写的操作,也就说对数据库读取数据的压力比较...

MYSQL数据库的五大安全防护措施

以技术为基础的企业里最有价值的资产莫过于是客户或者其数据库中的产品信息了。因此,在这样的企业中,保证数据库免受外界攻击是数据库管理的重要环节。很多数据库管理员并没有实施什么数据库保护措施,只是因为觉得...

docker安装mysql

准备工作已安装Docker环境(官方安装文档)终端/命令行工具(Linux/macOS/WSL)步骤1:拉取MySQL镜像打开终端执行以下命令,拉取官方MySQL镜像(默认最新版本):d...

Zabbix监控系统系列之六:监控 mysql

zabbix监控mysql1、监控规划在创建监控项之前要尽量考虑清楚要监控什么,怎么监控,监控数据如何存储,监控数据如何展现,如何处理报警等。要进行监控的系统规划需要对Zabbix很了解,这里只是...

详解MySQL的配置文件及优化

#头条创作挑战赛#在Windows系统中,MySQL服务器启动时最先读取的是my.ini这个配置文件。在Linux系统中,配置文件为my.cnf,其路径一般为/etc/my.cnf或/etc/mysq...

Mysql 几个批处理执行脚本

学习mysql过程中,需要创建测试数据,并让多人每人一个数据库连接并进行作业检查。整合部分批处理创建数据批量创建数据库DELIMITER$CREATEPROCEDURECreateDatab...

MySQL学到什么程度?才有可以在简历上写精通

前言如今互联网行业用的最多就是MySQL,然而对于高级Web面试者,尤其对于寻找30k下工作的求职者,很多MySQL相关知识点基本都会涉及,如果面试中,你的相关知识答的模糊和不切要点,基...

mysql 主、从服务器配置“Slave_IO_Running: Connecting” 问题分析

#在进行mysql主、从服务器配置时,”SHOWSLAVESTATUS;“查看从库状态Slave_IO_Runing,出现错误:“Slave_IO_Running:Connectin...

MYSQL数据同步

java开发工程师在实际的开发经常会需要实现两台不同机器上的MySQL数据库的数据同步,要解决这个问题不难,无非就是mysql数据库的数据同步问题。但要看你是一次性的数据同步需求,还是定时数据同步,亦...

「MySQL 8」MySQL 5.7都即将停只维护了,是时候学习一波MySQL 8了

MySQL8新特性选择MySQL8的背景:MySQL5.6已经停止版本更新了,对于MySQL5.7版本,其将于2023年10月31日停止支持。后续官方将不再进行后续的代码维护。另外,...

Prometheus监控mysql

通过Prometheus监控Mysql,我们需要在Mysql端安装一个mysql-exporter,然后Prometheus通过mysql-exporter暴露的端口抓取数据。1.安装一个MYSQL配...