从XCPC转后端开发——Java语法篇(三) 在上期文章中我们了解了 Java 的常用容器与 Collection 接口这期文章中我们来继续学习一下 Java 的Collections工具类。java.util.Collections是 Java 提供的一个操作集合的工具类它包含大量静态方法用于对Collection及其实现类如List、Set、Queue等进行操作同时也提供了一些针对Map的包装方法。排序操作在上期文章中我们学习了List接口并了解了ArrayList这个酷似 C 中vector的容器。那对于像 C 中的排序操作如vectorintv(n);sort(v.begin(),v.end());这样的操作Java 是如何对应实现的呢下面是对应的 Java 语法ListIntegerlistnewArrayList(Arrays.asList(3,1,4,1,5));Collections.sort(list);// 自然排序 → [1,1,3,4,5]Collections.sort(list,Comparator.reverseOrder());// 逆序排序Collections.reverse(list);// 反转Collections.shuffle(list);// 随机打乱Collections.swap(list,0,2);// 交换指定位置元素Collections.rotate(list,2);// 向右循环移动 2 位注意以上操作会依次改变list的状态注释中的结果只对第一行成立。这段 Java 代码的等效 C 代码如下vectorintlist{3,1,4,1,5};sort(list.begin(),list.end());// 自然排序sort(list.begin(),list.end(),greaterint());// 逆序排序reverse(list.begin(),list.end());// 反转random_device rd;// 随机打乱mt19937g(rd());shuffle(list.begin(),list.end(),g);swap(list[0],list[2]);// 交换指定位置rotate(list.begin(),list.end()-2,list.end());// 向右循环移动 2 位当然这些是不够的在实际中可能需要手写比较器。下面我们来看一下 Java 是怎么实现的实现 Comparable 接口Java 可以通过实现ComparableT接口并重写compareTo方法来完成自然排序classStudentimplementsComparableStudent{Stringname;intage;Student(Stringname,intage){this.namename;this.ageage;}OverridepublicintcompareTo(Studento){returnInteger.compare(this.age,o.age);// 按年龄升序}OverridepublicStringtoString(){returnname(age);}}// 使用ListStudentlistnewArrayList(List.of(newStudent(Tom,20),newStudent(Jerry,18)));Collections.sort(list);对应 C 的代码structStudent{string name;intage;// 重载 运算符按年龄升序booloperator(constStudento)const{returnthis-ageo.age;}};// 使用vectorStudentv{{Tom,20},{Jerry,18}};sort(v.begin(),v.end());// 使用 operator外部比较器 lambda和 C 类似Java 也可以通过外部比较器实现排序ListStudentlistnewArrayList(List.of(newStudent(Tom,20),newStudent(Jerry,18)));// 按姓名升序list.sort((a,b)-a.name.compareTo(b.name));// 按年龄降序list.sort((a,b)-Integer.compare(b.age,a.age));对应 C 代码vectorStudentv{{Tom,20},{Jerry,18}};// 按姓名升序sort(v.begin(),v.end(),[](constStudenta,constStudentb){returna.nameb.name;// 注意返回 bool});// 按年龄降序sort(v.begin(),v.end(),[](constStudenta,constStudentb){returna.ageb.age;});应用在有序容器上当然将比较器写在容器定义时也是可以的比如// 自然顺序Student 实现 ComparableTreeSetStudentset1newTreeSet();// 自定义比较器按姓名TreeSetStudentset2newTreeSet(Comparator.comparing(s-s.name));TreeMapStudent,IntegermapnewTreeMap(Comparator.comparingInt(s-s.age));// 小顶堆默认PriorityQueueIntegerminHeapnewPriorityQueue();// 大顶堆PriorityQueueIntegermaxHeapnewPriorityQueue(Comparator.reverseOrder());// 按年龄小顶堆PriorityQueueStudentpqnewPriorityQueue(Comparator.comparingInt(s-s.age));注意TreeSet/TreeMap如果比较器认为两个对象相等会去重或覆盖。例如按年龄比较时同年龄的学生会被视为同一个 key。对应 C// 自然顺序Student 重载 operatorsetStudents1;// 自定义比较器需在模板参数中指定autocmpByName[](constStudenta,constStudentb){returna.nameb.name;};setStudent,decltype(cmpByName)s2(cmpByName);mapStudent,int,decltype(cmpByName)m(cmpByName);// 大顶堆默认注意和 Java 相反priority_queueintmaxHeap;// 小顶堆priority_queueint,vectorint,greaterintminHeap;// 自定义比较器注意C 中 小于 规则构建的是大顶堆autocmpByAge[](constStudenta,constStudentb){returna.ageb.age;// 小顶堆};priority_queueStudent,vectorStudent,decltype(cmpByAge)pq(cmpByAge);需要注意的是Java 的Comparable.compareTo/Comparator.compare返回int三态负、0、正C 中std::sort的比较器返回bool两态true表示“排在前面”。但priority_queue的Compare语义与sort不同默认less得到大顶堆greater得到小顶堆。这是两者容易混淆的地方。查找和替换除了实现排序功能外Collections中还有很多好用的功能如最值等。下面是有关查找、替换功能的实现Collections.max(list);// 最大值空集合抛 NoSuchElementExceptionCollections.min(list);// 最小值Collections.binarySearch(list,3);// 二分查找需先排序Collections.frequency(list,1);// 出现次数Collections.replaceAll(list,1,9);// 替换所有Collections.fill(list,0);// 全部填充分别对应 C 的如下片段automaxItmax_element(list.begin(),list.end());// *maxIt空范围需检查autominItmin_element(list.begin(),list.end());// *minItboolfoundbinary_search(list.begin(),list.end(),3);// 需先排序返回 boolautocntcount(list.begin(),list.end(),1);// 出现次数replace(list.begin(),list.end(),1,9);// 替换所有fill(list.begin(),list.end(),0);// 全部填充注意max_element、min_element、binary_search、count、replace、fill等都在algorithm中。binary_search返回bool如果需要下标可以使用lower_bound。杂项除此之外还有一些功能也被实现了比如ListStringstrListnewArrayList();Collections.addAll(strList,a,b,c);// 批量添加Collections.copy(dest,src);// 复制dest.size() 必须 src.size()Collections.disjoint(list1,list2);// 判断是否无交集Collections.nCopies(5,x);// 返回 n 个重复元素不可变 ListCollections.reverseOrder();// 返回逆序比较器当然在不知道的情况下自己手写实现也是不错的选择总结通过前三篇文章的讲解你已经可以完成力扣中大多数算法题的 Java 代码了反复使用即可熟练上手