0Pricing
Java Academy · 课时

实际应用中的数组与集合排序

通过实际案例,将排序应用于商品列表、排行榜和活动日程

实际应用中的数组与集合排序 是 CoddyKit 上的免费 Java Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

实践中的排序

本课将排序技术应用于真实场景:产品目录、排行榜、事件安排以及搜索结果排名。

使用 Arrays.sort 对基本类型数组排序

基本类型数组使用 Arrays.sort() 时采用双轴快速排序——速度极快,平均时间复杂度为 O(n log n)。

int[] scores = {45, 90, 78, 62, 88, 33};
Arrays.sort(scores);
System.out.println(Arrays.toString(scores)); // [33, 45, 62, 78, 88, 90]

// Sort a range only
int[] data = {9, 3, 7, 1, 5};
Arrays.sort(data, 1, 4); // sort indices 1-3 only
System.out.println(Arrays.toString(data)); // [9, 1, 3, 7, 5]

使用 Arrays.sort 对对象数组排序

对于对象数组,Arrays.sort() 使用 TimSort(稳定排序)。您可以提供比较器来定义自定义顺序。

String[] names = {"Charlie", "Alice", "Bob", "Diana"};
Arrays.sort(names);
System.out.println(Arrays.toString(names)); // [Alice, Bob, Charlie, Diana]

// Custom order: by length, then alphabetically
Arrays.sort(names, Comparator.comparingInt(String::length).thenComparing(Comparator.naturalOrder()));
System.out.println(Arrays.toString(names)); // [Bob, Alice, Diana, Charlie]

Collections.sort 与 List.sort

两者都会在原列表上直接进行排序。List.sort() 是现代 Java 中更推荐的方式。

List<Integer> nums = new ArrayList<>(List.of(5, 2, 8, 1, 9, 3));

// Old way
Collections.sort(nums);
System.out.println(nums); // [1, 2, 3, 5, 8, 9]

// Modern way (same result)
nums.sort(Comparator.naturalOrder());
nums.sort(null); // null means natural order

// Descending
nums.sort(Comparator.reverseOrder());
System.out.println(nums); // [9, 8, 5, 3, 2, 1]

使用 Stream.sorted() 实现函数式风格

构建处理流水线时,请使用 stream().sorted()——它会生成新的排序流,而不会修改源数据。

List<String> cities = List.of("Tokyo", "London", "New York", "Paris", "Sydney");

// Sorted stream — source list unchanged
List<String> sorted = cities.stream()
    .sorted(Comparator.comparingInt(String::length).thenComparing(Comparator.naturalOrder()))
    .collect(Collectors.toList());

System.out.println(sorted);
// [Paris, Tokyo, London, Sydney, New York]

按值对映射排序

一个经典的面试问题:使用流和比较器按映射中的值进行排序。

import java.util.*;
import java.util.stream.*;

Map<String, Integer> scores = Map.of(
    "Alice", 95, "Bob", 87, "Charlie", 92, "Diana", 87
);

Map<String, Integer> sorted = scores.entrySet().stream()
    .sorted(Map.Entry.<String, Integer>comparingByValue(Comparator.reverseOrder())
        .thenComparing(Map.Entry.comparingByKey()))
    .collect(Collectors.toLinkedHashMap(
        Map.Entry::getKey, Map.Entry::getValue,
        (v1, v2) -> v1, LinkedHashMap::new));

sorted.forEach((k, v) -> System.out.println(k + ": " + v));
// Alice: 95 / Charlie: 92 / Bob: 87 / Diana: 87

使用 Collator 进行区域设置感知的排序

对于识别语言规则的字符串排序,请使用 java.text.Collator,而不是 String.compareTo——它可以处理重音、大小写以及特定区域设置的排序规则。

import java.text.*;
import java.util.*;

List<String> names = new ArrayList<>(List.of("éclair", "apple", "Über", "banana"));

Collator collator = Collator.getInstance(Locale.GERMAN);
names.sort(collator);
System.out.println(names); // locale-aware sort

按多个条件对对象排序

电子商务产品排序:先显示有库存的产品,然后按促销价格、评分,最后按名称排序。

record Product(String name, double price, double salePrice, double rating, boolean inStock) {}

Comparator<Product> bestFirst = Comparator
    .comparing(Product::inStock).reversed()           // in-stock first
    .thenComparingDouble(Product::salePrice)          // cheapest sale price
    .thenComparingDouble(Product::rating).reversed()  // highest rated
    .thenComparing(Product::name);                    // alphabetical tiebreak

按日期和时间对事件排序

使用实现 Comparable 的 java.time 类型,按时间顺序对事件日程进行排序。

import java.time.*;
import java.util.*;

record Event(String title, LocalDate date, LocalTime time) {}

List<Event> schedule = new ArrayList<>(List.of(
    new Event("Workshop",  LocalDate.of(2024,7,15), LocalTime.of(9, 0)),
    new Event("Keynote",   LocalDate.of(2024,7,14), LocalTime.of(10, 30)),
    new Event("Lunch Talk",LocalDate.of(2024,7,15), LocalTime.of(12, 0)),
    new Event("Hackathon", LocalDate.of(2024,7,14), LocalTime.of(9, 0))
));

schedule.sort(Comparator.comparing(Event::date).thenComparing(Event::time));
schedule.forEach(e -> System.out.println(e.date() + " " + e.time() + " " + e.title()));

使用排序获取前 N 个元素

高效查找前 N 个元素:按降序排序后取前 N 个,或者在大型数据集中使用 PriorityQueue。

List<Integer> values = List.of(42, 17, 88, 5, 73, 56, 91, 33);

// Simple approach: sort descending, take first 3
List<Integer> top3 = values.stream()
    .sorted(Comparator.reverseOrder())
    .limit(3)
    .collect(Collectors.toList());
System.out.println(top3); // [91, 88, 73]

// For very large datasets: PriorityQueue min-heap approach is O(n log k)
import java.util.PriorityQueue;
PriorityQueue<Integer> heap = new PriorityQueue<>(3);
for (int v : values) {
    heap.offer(v);
    if (heap.size() > 3) heap.poll();
}
System.out.println(new TreeSet<>(heap).descendingSet()); // [73, 88, 91]

使用排序进行去重

排序后,重复项会彼此相邻,因此可以在线性时间 O(n) 内进行检测。

int[] arr = {3, 1, 4, 1, 5, 9, 2, 6, 5};
Arrays.sort(arr); // sort first

// Remove duplicates in O(n) after sorting
int[] unique = Arrays.stream(arr).distinct().toArray();
System.out.println(Arrays.toString(unique)); // [1, 2, 3, 4, 5, 6, 9]

性能:选择排序方法

选择正确的排序方式:

  • 基本类型数组:Arrays.sort()——速度最快的原地快速排序
  • 实现 Comparable 的对象数组或列表:Collections.sort() 或 List.sort(null)
  • 多种排序顺序:使用带 thenComparing 的比较器链
  • 从大型流中获取前 N 个元素:PriorityQueue 或 Stream.sorted().limit(N)

快速检查

Java 在 Arrays.sort() 中对对象数组使用哪种排序算法?

回顾:实践中的数组和集合排序

关键要点:

  • 基本类型使用 Arrays.sort() 时采用双轴快速排序;对象使用 TimSort(稳定排序)
  • List.sort(比较器) 和 Collections.sort() 都是稳定的 TimSort
  • stream().sorted() 会生成新的排序流,而不会修改源数据
  • 按值对映射排序:entrySet().stream().sorted(Map.Entry.comparingByValue())
  • 使用 Collator 进行区域设置感知的字符串排序
  • 从大型数据中获取前 N 个元素时,容量为 k 的 PriorityQueue 比完整排序更高效

常见问题解答

「实际应用中的数组与集合排序」课时是免费的吗?

是的 — 「实际应用中的数组与集合排序」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「实际应用中的数组与集合排序」这节课中我会学到什么?

通过实际案例,将排序应用于商品列表、排行榜和活动日程 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「实际应用中的数组与集合排序」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Comparable 接口
  2. Comparator 与 Lambda 排序
  3. 使用 thenComparing 进行多关键字排序
  4. 实际应用中的数组与集合排序
← 返回 Java Academy