1.介绍
java.util.Collections 是 java 集合框架的一个工具类,主要用于 Collection 提供的通用算法;包含有各种有关集合操作的静态方法。此类不能实例化。
2.Collections.sort 排序
2.1 使用
// 假设 list 中的内容是 [2,6,1,5,2,9,8]
// 默认排列(正序)
Collections.sort(list);
// 测试结果:1 2 2 5 6 8 9
// 倒序排序
Collections.sort(list, Collections.<String>reverseOrder());
// 测试结果:9 8 6 5 2 2 1
2.2 源码简述
Collections.sort调用的是List接口的sort默认方法- 在
List.sort方法中最终调用的是Arrays.sort方法进行排序 - 在
Arrays.sort中根据LegacyMergeSort.userRequested选择不同的算法排序(一般为 false)- 如果为
true,调用legacyMergeSort进行归并排序 - 如果为
false,调用TimeSort.sort方法- 如果元素个数小于 32,则使用 二分插入排序
- 如果元素个数大于 32,则使用 分段排序
- 如果为
// Collections$sort
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
// Collections$sort
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
// List$sort
default void sort(Comparator<? super E> c) {
// 容器内元素转换为数组
Object[] a = this.toArray();
// 调用 Arrays.sort 方法根据 比较器 进行排序
Arrays.sort(a, (Comparator) c);
// 获取容器的列表迭代器
ListIterator<E> i = this.listIterator();
// 遍历数组;通过迭代器将排序后的值设置回容器
for (Object e : a) {
i.next();
i.set((E) e);
}
}
// Arrays$sort
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
// 归并排序
legacyMergeSort(a, c);
else
// 调用 TimeSort 的排序方法
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
// 倒序排列的比较器
public static <T> Comparator<T> reverseOrder() {
return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
}
private static class ReverseComparator
implements Comparator<Comparable<Object>>, Serializable {
private static final long serialVersionUID = 7207038068494060240L;
static final ReverseComparator REVERSE_ORDER
= new ReverseComparator();
// 核心:通过调用 c2 的 compareTo() 方法进行比较,从而返回倒序的结果
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c2.compareTo(c1);
}
private Object readResolve() { return Collections.reverseOrder(); }
@Override
public Comparator<Comparable<Object>> reversed() {
return Comparator.naturalOrder();
}
}
3.Collections.binarySearch 二分查找
3.1 使用
// 假设 list 中的内容是 [2,5,6,9,12]
Collections.binarySearch(list, 5);
// 结果:1
例子:
3.2 源码简述
- 实现了
RandomAccess接口或容器长度小于 ,则调用indexedBinarySearch()ArraysList实现了该接口,而LinkedList没有实现该接口;如果容器长度太长,通过索引定位元素的方式,对于LinkedList来说十分耗时- 通过索引获取值
- 否则调用
iteratorBinarySearch()- 通过迭代器获取值
public static <T>
int binarySearch(List<? extends Comparable<? super T>> list, T key) {
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else
return Collections.iteratorBinarySearch(list, key);
}
private static <T>
int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
int low = 0;
int high = list.size()-1;
while (low <= high) {
// 求中间结点索引
int mid = (low + high) >>> 1;
// 从容器中获取值
Comparable<? super T> midVal = list.get(mid);
// 与 key 进行比较
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
private static <T>
int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key)
{
int low = 0;
int high = list.size()-1;
// 获取列表迭代器
ListIterator<? extends Comparable<? super T>> i = list.listIterator();
while (low <= high) {
// 求中间结点索引
int mid = (low + high) >>> 1;
// 通过迭代器获取值
Comparable<? super T> midVal = get(i, mid);
// 与 key 比较
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
4.Collections.shuffle 洗牌算法
4.1 使用
List<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d","e"));
Collections.shuffle(list);
// 结果:[b, a, d, c, e]
Collections.shuffle(list,new Random(2));
// 结果:[b, c, a, d, e]
例子:
4.2 源码简述
private static Random r;
public static void shuffle(List<?> list) {
Random rnd = r;
if (rnd == null)
r = rnd = new Random(); // harmless race.
shuffle(list, rnd);
}
public static void shuffle(List<?> list, Random rnd) {
int size = list.size();
// 如果长度小于 5 或者继承了 RandomAccess 接口,则进入该分支
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i=size; i>1; i--)
// 遍历列表,每遍历一个位置,就随机一个新的索引,并交换两者的元素
swap(list, i-1, rnd.nextInt(i));
} else {
// 将列表转换为数组
Object[] arr = list.toArray();
// 同上一个分支持操作一样
for (int i=size; i>1; i--)
swap(arr, i-1, rnd.nextInt(i));
// 通过列表迭代器,将数组中的排列顺序设置回列表
ListIterator it = list.listIterator();
for (int i=0; i<arr.length; i++) {
it.next();
it.set(arr[i]);
}
}
}
5.Collections.rotate 旋转算法
5.1 使用
List<String> list = new LinkedList<String>(Arrays.asList("1","2","3","4","5"));
Collections.rotate(list, 2);
// 结果:[4, 5, 1, 2, 3]
例子:
5.2 源码简述
public static void rotate(List<?> list, int distance) {
if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD)
// 实现了 RandomAccess 接口或者列表长度小于 100,则通过 rotate1() 实现
rotate1(list, distance);
else
// 否则通过 rotate2() 实现
rotate2(list, distance);
}
private static <T> void rotate1(List<T> list, int distance) {
int size = list.size();
if (size == 0)
return;
// 获取旋转的位置
distance = distance % size;
if (distance < 0)
distance += size;
if (distance == 0)
return;
// cycleStart:旋转开始的索引
// nMoved:已旋转的元素个数
for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
// 获取在旋转开始处的元素
T displaced = list.get(cycleStart);
int i = cycleStart;
do {
// displaced元素 旋转后到达的位置
i += distance;
if (i >= size)
i -= size;
// 将 displaced元素 设置在 i 处,并返回 i 处原来的元素
displaced = list.set(i, displaced);
nMoved ++;
} while (i != cycleStart);
}
}
private static void rotate2(List<?> list, int distance) {
int size = list.size();
if (size == 0)
return;
// 定位拆链位置:找到旋转后,从首结点开始的链表个数
// 例如 [1,2,3,4,5],distance=2,旋转后 [4,5,1,2,3],可知 mid=3
int mid = -distance % size;
if (mid < 0)
mid += size;
if (mid == 0)
return;
// 翻转 [0,mid) 链表
reverse(list.subList(0, mid));
// 翻转 [mid,size) 链表
reverse(list.subList(mid, size));
// 翻转整个链表
reverse(list);
}
6.Collections.min 和 Collections.max
6.1 使用
List<Integer> list = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6));
Integer min = Collections.min(list);
// 结果:min = 1
Integer max = Collections.max(list);
// 结果:max = 6
6.2 源码简述
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) {
// 获取集合迭代器
Iterator<? extends T> i = coll.iterator();
// 将第一个元素作为候选元素
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
// 如果下一个元素 next 比候选元素 candidate 小,则更新候选元素
if (next.compareTo(candidate) < 0)
candidate = next;
}
return candidate;
}
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
// 如果下一个元素 next 比候选元素 candidate 大,则更新候选元素
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;
}
7.Collections.replaceAll 替换算法
7.1 使用
List<String> list = new ArrayList<String>(Arrays.asList("7", "2", "8", "8", "6", "8", "5"));
// 原列表:[7, 2, 8, 8, 6, 8, 5]
Collections.replaceAll(list, "8", "9");
// 替换后的列表:[7, 2, 9, 9, 6, 9, 5]
7.2 源码简述
public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) {
boolean result = false;
int size = list.size();
// 当列表长度小于 11 或 list实现了 RandomAccess 接口
if (size < REPLACEALL_THRESHOLD || list instanceof RandomAccess) {
// for 循环遍历,并通过索引的方式设置值
if (oldVal==null) {
for (int i=0; i<size; i++) {
if (list.get(i)==null) {
list.set(i, newVal);
result = true;
}
}
} else {
for (int i=0; i<size; i++) {
if (oldVal.equals(list.get(i))) {
list.set(i, newVal);
result = true;
}
}
}
} else {
// for 循环遍历,并通过迭代器的方式设置值
ListIterator<T> itr=list.listIterator();
if (oldVal==null) {
for (int i=0; i<size; i++) {
if (itr.next()==null) {
itr.set(newVal);
result = true;
}
}
} else {
for (int i=0; i<size; i++) {
if (oldVal.equals(itr.next())) {
itr.set(newVal);
result = true;
}
}
}
}
return result;
}
8.Collections.indexOfSubList 定位列表位置
8.1 使用
List<String> list = new ArrayList<String>(Arrays.asList("7", "2", "8", "6", "8", "5"));
int idx = Collections.indexOfSubList(list, Arrays.asList("8", "6"));
// 结果:2
8.2 源码简述
public static int indexOfSubList(List<?> source, List<?> target) {
int sourceSize = source.size();
int targetSize = target.size();
// 计算最大的开始索引位置
int maxCandidate = sourceSize - targetSize;
// 如果 source 列表长度小于 35 或者 source 和 target 列表都实现了 RandomAccess 接口
if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
(source instanceof RandomAccess && target instanceof RandomAccess)) {
nextCand:
// for 循环遍历开始索引位置
for (int candidate = 0; candidate <= maxCandidate; candidate++) {
// 遍历两个列表中值是否相等
for (int i=0, j=candidate; i<targetSize; i++, j++)
if (!eq(target.get(i), source.get(j)))
// 如果有值不相等,则回到 nextCand 标签处重新开始
continue nextCand;
return candidate; // All elements of candidate matched target
}
} else {
// 处理逻辑和上面相似,不同点在于通过列表迭代器遍历列表
ListIterator<?> si = source.listIterator();
nextCand:
for (int candidate = 0; candidate <= maxCandidate; candidate++) {
ListIterator<?> ti = target.listIterator();
for (int i=0; i<targetSize; i++) {
if (!eq(ti.next(), si.next())) {
// 不相等时,将 si 指针回退到 target 列表开始处
for (int j=0; j<i; j++)
si.previous();
continue nextCand;
}
}
return candidate;
}
}
return -1; // No candidate matched the target
}