Java Collections类的shuffle和sort方法详解

Java Collections 类的 shuffle()sort() 方法详解

java.util.Collections 是 Java 集合框架的工具类,提供了大量静态方法操作 CollectionList。其中 shuffle() 用于随机打乱列表元素,sort() 用于排序列表元素。

两者都是原地操作(in-place),直接修改传入的 List,不返回新列表。

1. Collections.shuffle() —— 洗牌方法

方法签名(两个重载)

public static void shuffle(List<?> list)
public static void shuffle(List<?> list, Random rnd)
  • 第一个:使用默认的随机源(内部使用 Random)。
  • 第二个:使用指定的 Random 对象,可实现可重复/确定性洗牌(相同 seed 结果完全相同)。

核心算法:Fisher-Yates Shuffle(现代版 / Knuth Shuffle)

  • 时间复杂度:O(n)(线性时间)
  • 空间复杂度:O(1)(原地交换,仅小量辅助变量)
  • 保证所有排列等概率出现。

源码实现(JDK 最新版核心逻辑):

public static void shuffle(List<?> list, Random rnd) {
    int size = list.size();
    if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
        // 小列表 或 ArrayList 等随机访问列表:直接原地交换
        for (int i = size; i > 1; i--)
            swap(list, i - 1, rnd.nextInt(i));
    } else {
        // LinkedList 等非随机访问列表:先转数组,打乱后再写回
        Object[] arr = list.toArray();
        for (int i = size; i > 1; i--)
            swap(arr, i - 1, rnd.nextInt(i));
        ListIterator it = list.listIterator();
        for (Object e : arr) {
            it.next();
            it.set(e);
        }
    }
}

SHUFFLE_THRESHOLD 通常为 5)

经典 Fisher-Yates 过程(从后往前):

  • 从最后一个元素开始,到第 2 个元素为止。
  • 当前位置 i[0, i] 范围内随机一个位置交换。
  • 这样每个元素被交换到的概率完全均匀。

使用示例

import java.util.*;

public class ShuffleDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));

        System.out.println("原始: " + list);
        Collections.shuffle(list);
        System.out.println("随机打乱: " + list);

        // 确定性打乱(相同 seed 结果相同)
        Random rnd = new Random(42);
        Collections.shuffle(list, rnd);
        System.out.println("固定种子打乱: " + list);
    }
}

注意事项

  • 只接受 List,其他集合(如 SetMap)需先转为 List
  • UnsupportedOperationException:如果列表不支持 set 操作(如 Arrays.asList() 返回的固定长度列表)。
  • 线程不安全,多线程需外部同步。

2. Collections.sort() —— 排序方法

方法签名(两个重载)

public static <T extends Comparable<? super T>> void sort(List<T> list)   // 自然顺序
public static <T> void sort(List<T> list, Comparator<? super T> c)       // 自定义比较器

内部实现(JDK 8+)

public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);                    // 自然顺序
}

public static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}

// List 接口默认方法(实际干活的地方)
default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);     // 调用 Arrays.sort(TimSort)
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}
  • 算法TimSort(归并排序的优化版,Java 7+ 引入)
  • 时间复杂度:O(n log n)
  • 空间复杂度:O(n)(临时数组)
  • 稳定排序(相等元素保持相对顺序)
  • 先转数组 → Arrays.sort() 排序 → 写回列表。

Arrays.sort() 的区别

特性Collections.sort(List)Arrays.sort(数组)
操作对象List(ArrayList、LinkedList 等)数组(基本类型 + 对象数组)
算法(对象)TimSort(稳定)TimSort(稳定)
算法(基本类型)不支持Dual-Pivot QuickSort(更快,但不稳定
稳定性稳定对象稳定,基本类型不稳定
性能稍慢(多一次转数组)更快,尤其基本类型
使用场景动态列表排序数组、追求极致性能

使用示例

List<String> list = new ArrayList<>(Arrays.asList("Geeks", "For", "Geeks", "Dear", "Is", "Superb"));

// 1. 自然升序(Comparable)
Collections.sort(list);
System.out.println("升序: " + list);   // [Dear, For, Geeks, Geeks, Is, Superb]

// 2. 降序(Comparator)
Collections.sort(list, Collections.reverseOrder());
System.out.println("降序: " + list);   // [Superb, Is, Geeks, Geeks, For, Dear]

// 3. 自定义 Comparator(按长度排序)
Collections.sort(list, (a, b) -> a.length() - b.length());
System.out.println("按长度: " + list);

自定义对象排序

class Student implements Comparable<Student> {
    int id;
    String name;
    // 实现 compareTo...
}

Collections.sort(students);                    // 自然顺序
Collections.sort(students, new SortByName());  // 或 Comparator

异常

  • ClassCastException:元素未实现 Comparable 且未传 Comparator
  • NullPointerException:列表或 Comparator 为 null。

总结对比

方法作用算法时间复杂度是否稳定适用类型推荐场景
shuffle()随机打乱Fisher-YatesO(n)List抽奖、随机队列、洗牌
sort()排序TimSortO(n log n)List需要稳定排序的业务场景
Arrays.sort()排序Dual-Pivot QS / TimSortO(n log n)基本类型否数组高性能、基本类型数组

一句话记忆

  • 随机Collections.shuffle(list)
  • 有序Collections.sort(list)list.sort(...)(JDK 8+ 推荐)

需要完整可运行的 Demo 项目、自定义对象排序案例、或与 Stream API 结合的写法,随时告诉我,我可以继续补充!

文章已创建 5021

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部