前言 由于左老师的课上用的是java来教授,而我比较熟悉c++,所以我在借助gpt帮我将代码改为c++的同时,还和它对两种语言的相同和不同之处进行了比较详细的探讨。 探讨的内容包括:
比较器的返回值差异
函数对象声明的区别
优雅 - 翩翩起舞的 lambda
java 的 key 都是什么意思
c++: auto vs it JAVA 的良好特性——默认传递引用、数组自带大小信息
这是来自左老师的比较器代码(JAVA)
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 import java.util.ArrayList;import java.util.Arrays;import java.util.Comparator;import java.util.TreeMap;public class Code01_Comparator { public static class Student { public String name; public int id; public int age; public Student (String name, int id, int age) { this .name = name; this .id = id; this .age = age; } } public static class IdShengAgeJiangOrder implements Comparator <Student> { @Override public int compare (Student o1, Student o2) { return o1.id != o2.id ? (o1.id - o2.id) : (o2.age - o1.age); } } public static class IdAscendingComparator implements Comparator <Student> { @Override public int compare (Student o1, Student o2) { return o1.id - o2.id; } } public static class IdDescendingComparator implements Comparator <Student> { @Override public int compare (Student o1, Student o2) { return o2.id - o1.id; } } public static class IdInAgeDe implements Comparator <Student> { @Override public int compare (Student o1, Student o2) { return o1.id != o2.id ? o1.id - o2.id : (o2.age - o1.age); } } public static void printStudents (Student[] students) { for (Student student : students) { System.out.println("Name : " + student.name + ", Id : " + student.id + ", Age : " + student.age); } } public static void printArray (Integer[] arr) { if (arr == null ) { return ; } for (int i = 0 ; i < arr.length; i++) { System.out.print(arr[i] + " " ); } System.out.println(); } public static class MyComp implements Comparator <Integer> { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } } public static class AComp implements Comparator <Integer> { @Override public int compare (Integer arg0, Integer arg1) { return arg1 - arg0; } } public static void main (String[] args) { Integer[] arr = { 5 , 4 , 3 , 2 , 7 , 9 , 1 , 0 }; Arrays.sort(arr, new AComp ()); for (int i = 0 ; i < arr.length; i++) { System.out.println(arr[i]); } System.out.println("===========================" ); Student student1 = new Student ("A" , 4 , 40 ); Student student2 = new Student ("B" , 4 , 21 ); Student student3 = new Student ("C" , 3 , 12 ); Student student4 = new Student ("D" , 3 , 62 ); Student student5 = new Student ("E" , 3 , 42 ); Student[] students = new Student [] { student1, student2, student3, student4, student5 }; System.out.println("第一条打印" ); Arrays.sort(students, new IdShengAgeJiangOrder ()); for (int i = 0 ; i < students.length; i++) { Student s = students[i]; System.out.println(s.name + "," + s.id + "," + s.age); } System.out.println("第二条打印" ); ArrayList<Student> studentList = new ArrayList <>(); studentList.add(student1); studentList.add(student2); studentList.add(student3); studentList.add(student4); studentList.add(student5); studentList.sort(new IdShengAgeJiangOrder ()); for (int i = 0 ; i < studentList.size(); i++) { Student s = studentList.get(i); System.out.println(s.name + "," + s.id + "," + s.age); } System.out.println("第三条打印" ); student1 = new Student ("A" , 4 , 40 ); student2 = new Student ("B" , 4 , 21 ); student3 = new Student ("C" , 4 , 12 ); student4 = new Student ("D" , 4 , 62 ); student5 = new Student ("E" , 4 , 42 ); TreeMap<Student, String> treeMap = new TreeMap <>((a, b) -> (a.id - b.id)); treeMap.put(student1, "我是学生1,我的名字叫A" ); treeMap.put(student2, "我是学生2,我的名字叫B" ); treeMap.put(student3, "我是学生3,我的名字叫C" ); treeMap.put(student4, "我是学生4,我的名字叫D" ); treeMap.put(student5, "我是学生5,我的名字叫E" ); for (Student s : treeMap.keySet()) { System.out.println(s.name + "," + s.id + "," + s.age); } } }
gpt优化后的c++代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 #include <iostream> #include <vector> #include <algorithm> #include <map> struct Student { std::string name; int id; int age; Student (const std::string& name, int id, int age) : name (name), id (id), age (age) {} }; bool idShengAgeJiangOrder (const Student& o1, const Student& o2) { return o1.id != o2.id ? (o1.id < o2.id) : (o2.age < o1.age); } bool idAscendingComparator (const Student& o1, const Student& o2) { return o1.id < o2.id; } bool idDescendingComparator (const Student& o1, const Student& o2) { return o2.id < o1.id; } bool idInAgeDe (const Student& o1, const Student& o2) { return o1.id != o2.id ? (o1.id < o2.id) : (o2.age < o1.age); } bool acomp (const int & a, const int & b) { return a < b; } void printStudents (const std::vector<Student>& students) { for (const Student& student : students) { std::cout << "Name: " << student.name << ", Id: " << student.id << ", Age: " << student.age << std::endl; } } void printArray (const std::vector<int >& arr) { for (int i = 0 ; i < arr.size (); i++) { std::cout << arr[i] << " " ; } std::cout << std::endl; } int main () { std::vector<int > arr = { 5 , 4 , 3 , 2 , 7 , 9 , 1 , 0 }; std::sort (arr.begin (), arr.end (), acomp); printArray (arr); std::vector<Student> students = { {"A" , 4 , 40 }, {"B" , 4 , 21 }, {"C" , 3 , 12 }, {"D" , 3 , 62 }, {"E" , 3 , 42 } }; std::sort (students.begin (), students.end (), idShengAgeJiangOrder); printStudents (students); std::map<Student, std::string, decltype (idAscendingComparator) *> studentMap (idAscendingComparator) ; studentMap.insert ({ {"A" , 4 , 40 }, "I am student 1, my name is A" }); studentMap.insert ({ {"B" , 4 , 21 }, "I am student 2, my name is B" }); studentMap.insert ({ {"C" , 4 , 12 }, "I am student 3, my name is C" }); studentMap.insert ({ {"D" , 4 , 62 }, "I am student 4, my name is D" }); studentMap.insert ({ {"E" , 4 , 42 }, "I am student 5, my name is E" }); for (const auto & entry : studentMap) { const Student& s = entry.first; std::cout << s.name << "," << s.id << "," << s.age << std::endl; } return 0 ; }
构造函数的区别: 首先,我发现两种语言在构造函数上不太一样。
语言
代码示例
初始化方式
C++
cpp Student(string name, int id) : name(name), id(id) {}
初始化列表
Java
java public Student(String name, int id) { this.name = name; this.id = id; }
构造函数体内赋值
我发现原代码没有用初始化列表来赋值,于是查询资料:
1 2 在 Java 中,构造函数的语法不支持像 C++ 中的初始化列表一样的方式来进行构造时赋值。在 Java 中,你需要在构造函数的方法体内手动对成员变量进行赋值。 如果你在意初始化效率,可以考虑使用 Java 中的双重检查锁定等方式来优化对象的创建过程。
“双重检查锁”通常用于实现单例模式,这意味着在整个应用程序中只有一个实例。通过使用双重检查锁,可以在多线程环境中确保只有一个线程能够成功初始化对象,并且其他线程会等待或被阻塞,以避免并发初始化的问题。
我立马联想到了c++中的“静态对象”,在C++中,可以使用静态成员变量来实现类级别的单例对象。静态成员变量只在类的生命周期内存在一个实例,并且它在类加载时被初始化。这样,每次使用这个类的对象时,都是引用同一个静态对象实例。
但是,查阅资料知道,虽然这两种方式都可以实现对象的单例特性,但在细节上存在一些差异。双重检查锁主要用于在多线程环境下确保单例对象的正确初始化,而C++的静态对象则是一种在类级别上实现单例的方式,不涉及多线程的同步问题。
函数对象声明的区别
特点
Java
C++
实现方式
实现Comparator接口,重写compare方法
创建函数对象类,重载函数调用操作符()
返回值
整数值,负数表示o1小于o2,正数表示o1大于o2
布尔值,true表示o1小于o2,false表示o1大于o2
命名空间
需要使用类名限定
可在局部或命名空间内使用
比较规则
返回负数、0、正数分别表示小于、等于、大于
返回true表示小于,false表示大于
示例: 1 2 3 4 5 6 7 8 public static class MyComp implements Comparator <Integer> { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } }
1 2 3 4 5 6 class MyComp {public : bool operator () (const int & o1, const int & o2) const { return o2 < o1; } };
java的这些key都是什么意思?
java
public: 是一个访问修饰符,表示被修饰的类、方法或变量可以在任何地方被访问,没有访问限制。
static: 是一个关键字,用于创建静态成员,包括静态方法、静态变量等。静态成员属于类本身,而不是类的实例。可以通过类名直接访问静态成员,而无需创建对象。
class: 是一个关键字,用于定义类。类是 Java 中用于创建对象的模板,它包含属性(成员变量)和方法。 综合起来,当使用 public static 修饰类或方法时,具体含义如下: ublic class: 定义一个公共类,可以被其他类访问。公共类可以在任何地方被使用。
public static class: 定义一个公共静态内部类。静态内部类是一个嵌套在其他类中的类,但它与外部类的实例无关,可以通过外部类名直接访问,无需创建外部类的对象。
public static method: 定义一个公共静态方法。静态方法属于类而不是类的实例,可以通过类名直接调用,无需创建对象。
而c++就比较熟悉:class 代表声明类,内部用public、private、protected区分访问权限。
三目运算符 return o1.id != o2.id ? (o1.id < o2.id) \ 简洁,美观~
优雅-翩翩起舞的lambda C++11引入的特性:Lambda表达式。
Lambda 表达式是C++11引入的特性,它允许你在需要的地方创建匿名的、一次性使用的函数。
例如,在sort函数中,可以直接调用:1 sort (arr.begin (), arr.end (), [](int a, int b) { return a < b; });
创建treeMap,也可以直接调用:1 TreeMap<Student, String> treeMap = new TreeMap <>((a, b) -> a.id - b.id);
Map vs TreeMap 1 std::map<Student, std::string, decltype (idAscendingComparator) *> studentMap (idAscendingComparator) ;
1 TreeMap<Student, String> treeMap = new TreeMap <>((a, b) -> (a.id - b.id));
特点
C++
Java
数据结构
std::map studentMap;
TreeMap treeMap;
有序映射
有序映射
有序映射
自定义比较器
是
是
比较器设置方式
在创建实例后通过函数指针设置
在创建实例时通过 Lambda 表达式设置
Lambda 表达式
适用
适用
代码示例
std::map<Student, std::string> studentMap(idAscendingComparator);
TreeMap<Student, String> treeMap = new TreeMap<>((a, b) -> (a.id - b.id));
When input data whose key has already been in it, both Map andTreeMap will not cover the previous data of the same key, and the new data will be discarded and unaccepted.
c++: auto vs it 1 2 3 4 5 6 7 for (const auto& entry : studentMap) { const Student& s = entry.first; std::string s1 = entry.second; std::cout << s.name << "," << s.id << "," << s.age<<" "; std::cout << s1<< std::endl; }
看到这一行,我坐不住了,心想,auto有没有可以替代的方案? 于是,查阅资料,得到如下:1 2 3 4 5 6 7 8 std::map<Student, std::string, decltype(idAscendingComparator)*>::const_iterator it; for (it = studentMap.begin(); it != studentMap.end(); ++it) { const Student& s = it->first; std::string s1 = it->second; std::cout << s.name << "," << s.id << "," << s.age << " "; std::cout << s1 << std::endl; }
也就是说,可以用it来代替auto,只不过要使用 std::map 的迭代器类型,但会使代码变得更冗长一些。
总的来说,使用 auto 是更为简洁和灵活的方式,因为它允许编译器根据上下文来推断类型。如果你手动指定类型,需要确保类型匹配并且正确。
JAVA的良好特性 默认传递引用 数组自带大小信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class ArrayExample { static void processArray (int [] arr) { for (int num : arr) { System.out.print(num + " " ); } System.out.println(); } static void process2DArray (int [][] arr) { for (int [] row : arr) { for (int num : row) { System.out.print(num + " " ); } System.out.println(); } } public static void main (String[] args) { int [] arr1 = {1 , 2 , 3 , 4 , 5 }; int [][] arr2 = {{1 , 2 , 3 }, {4 , 5 , 6 }}; processArray(arr1); process2DArray(arr2); } }
相比之下,c++的特性是最难绷的,起码上述Java的两个特性c++都没有:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <iostream> void processArray (int arr[], int size) { for (int i = 0 ; i < size; ++i) { std::cout << arr[i] << " " ; } std::cout << std::endl; } void process2DArray (int arr[][3 ], int rows, int cols) { for (int i = 0 ; i < rows; ++i) { for (int j = 0 ; j < cols; ++j) { std::cout << arr[i][j] << " " ; } std::cout << std::endl; } } int main () { int arr1[] = {1 , 2 , 3 , 4 , 5 }; int arr2[][3 ] = {{1 , 2 , 3 }, {4 , 5 , 6 }}; processArray (arr1, 5 ); process2DArray (arr2, 2 , 3 ); return 0 ; }
【完】