一丶概述
Collections在之前关于集合的文章中有说到Collections是集合工具类,提供一些相关算法,然而从事Android开发,数据基本都由后台处理,很少用到,面试问到话绝对答不上,这里就说说源码与用法。
二丶常见案例
/**
* <pre>
* author : JinBiao
* CSDN : http://my.csdn.net/DT235201314
* time : 2017/12/11
* desc : 集合工具类Collections 常见方法demo
* version: 1.0
* </pre>
*/public class CollectionsDemo {
public static void main(String[] args){
ArrayList nums=new ArrayList();
nums.add(12);
nums.add(-5);
nums.add(8);
Collections.sort(nums);//[-5, 8, 12]
System.out.println(nums);
nums.add(7);
Collections.reverse(nums);
System.out.println(nums);//[7, 12, 8, -5]
Collections.shuffle(nums);//随机排序
System.out.println(nums);//假定此刻为:[12, 7, -5, 8]
nums.add(10);
System.out.println(nums);//[12, 8, 7, -5, 10]
Collections.rotate(nums, 3); //rotate操作,正数是将nums的后3个数整体搬移到前面,负数是将前面3个数整体搬移到后面。
System.out.println(nums);//[7, -5, 10, 12, 8]
Collections.rotate(nums, -2);
System.out.println(nums);//[10, 12, 8, 7, -5]
//查找替换操作
nums.add(7);
System.out.println(Collections.max(nums));//12
System.out.println(Collections.min(nums));//-5
Collections.replaceAll(nums, 7, 9);//将num中所有7替换为9[10, 12, 8, 9, -5, 9]
System.out.println(nums);
System.out.println(Collections.frequency(nums, 9));//2
Collections.sort(nums);//只有排序了才能用二分查找
System.out.println(Collections.binarySearch(nums, 10));//4
}
}/**运行结果:
[-5, 8, 12]
[7, 12, 8, -5]
[7, 12, -5, 8]
[7, 12, -5, 8, 10]
[-5, 8, 10, 7, 12]
[10, 7, 12, -5, 8]
12
-5
[10, 9, 12, -5, 8, 9]
2
4
*/三丶源码分析
(1)sort()排序方法
/**
* List中的所有元素必须实现Compareable接口,即每个 元素必须是可比的。
* 算法的实现原理为: 把指定的List转化为一个对象数组,对数组进行排序,然后迭代List的每一个元素,
* 在同样的位置重新设置数组中排好序的元素
*/public static <T extends Comparable<? super T>> void sort(List<T> list) { if (list.getClass() == ArrayList.class) { //transient Object[] elementData
// 用transient关键字标记的成员变量不参与序列化过程。
Arrays.sort(((ArrayList) list).elementData, 0, list.size()); return;
}
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator(); for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}/**
* 传一个实现了Comparator接口的对象进来。 c.compare(o1,o2);来比较两个元素
*/public static <T> void sort(List<T> list, Comparator<? super T> c) { if (list.getClass() == ArrayList.class) {
Arrays.sort(((ArrayList) list).elementData, 0, list.size(), (Comparator) c); return;
}
Object[] a = list.toArray();
Arrays.sort(a, (Comparator)c);
ListIterator<T> i = list.listIterator(); for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}Comparable && Comparator区别与源码分析
(2)binarySearch()二分查找方法
/**
* 使用二分查找在指定List中查找指定元素key。 List中的元素必须是有序的。如果List中有多个key,不能确保哪个key值被找到。
* 如果List不是有序的,返回的值没有任何意义
*
* 对于随机访问列表来说,时间复杂度为O(log(n)),比如1024个数只需要查找log2(1024)=10次,
* log2(n)是最坏的情况,即最坏的情况下都只需要找10次
* 对于链表来说,查找中间元素的时间复杂度为O(n),元素比较的时间复杂度为O(log(n))
*
* @return 查找元素的索引。如果返回的是负数表明找不到此元素,但可以用返回值计算
* 应该将key插入到集合什么位置,任然能使集合有序(如果需要插入key值的话)。 公式:point = -i - 1
*
*/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);
}/**
* 使用索引化二分查找。 size小于5000的链表也用此方法查找
*/private static <T>int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) { int low = 0; int high = list.size()-1; while (low <= high) { // >>>1:无符号右移,忽略符号位,空位都以0补齐
int mid = (low + high) >>> 1;//相当于无符号除以2
Comparable<? super T> midVal = list.get(mid); // 指定元素与中间值比较
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); 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> T get(ListIterator<? extends T> i, int index) {
T obj = null; int pos = i.nextIndex(); // 根据当前迭代器的位置确定是向前还是向后遍历找中间值
if (pos <= index) { do {
obj = i.next();
} while (pos++ < index);
} else { do {
obj = i.previous();
} while (--pos > index);
} return obj;
}/**
* 提供实现了Comparator接口的对象比较元素
*/public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) { if (c==null) return binarySearch((List<? extends Comparable<? super T>>) list, key); if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD) return Collections.indexedBinarySearch(list, key, c); else
return Collections.iteratorBinarySearch(list, key, c);
}private static <T> int indexedBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
int low = 0;
int high = l.size()-1; while (low <= high) {
int mid = (low + high) >>> 1;
T midVal = l.get(mid);
int cmp = c.compare(midVal, 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 T> l, T key, Comparator<? super T> c) {
int low = 0;
int high = l.size()-1;
ListIterator<? extends T> i = l.listIterator(); while (low <= high) {
int mid = (low + high) >>> 1;
T midVal = get(i, mid);
int cmp = c.compare(midVal, 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}(3)reverse()反序方法
/**
* 逆序排列指定列表中的元素
*/public static void reverse(List<?> list) { int size = list.size(); //size小于18的链表或是基于随机访问的列表
if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) { for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j);
} else {
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size); // 基于迭代器的逆序排列算法 前后对换
for (int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
}
}
}/**
* 交换List中两个位置的值
*/public static void swap(List<?> list, int i, int j) {
final List l = list;
l.set(i, l.set(j, l.get(i)));
}(4)shuffle()随机混排方法
/**
* 对指定列表中的元素进行混排
*/public static void shuffle(List<?> list) {
Random rnd = r; if (rnd == null)
r = rnd = new Random(); // harmless race.
shuffle(list, rnd);
}private static Random r;/**
* 提供一个随机数生成器对指定List进行混排
* 基本算法思想为: 逆向遍历list,从最后一个元素到第二个元素,然后重复交换当前位置 与随机产生的位置的元素值。
* 如果list不是基于随机访问并且其size>5,会先把List中的复制到数组中, 然后对数组进行混排,再把数组中的元素重新填入List中。
* 这样做为了避免迭代器大跨度查找元素影响效率
*/public static void shuffle(List<?> list, Random rnd) { int size = list.size(); if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) { for (int i=size; i>1; i--) // 从i-1个位置开始与随机位置元素交换值
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)); // 然后把数组中的元素重新填入List
ListIterator it = list.listIterator(); for (int i=0; i<arr.length; i++) {
it.next();
it.set(arr[i]);
}
}
}/**
* 交换数组中两个位置的值
*/private static void swap(Object[] arr, int i, int j) {
Object tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}(5)fill()替换方法
/**
* 用obj替换List中的所有元素 size<25 依次遍历赋值即可
*/public static <T> void fill(List<? super T> list, T obj) { int size = list.size(); if (size < FILL_THRESHOLD || list instanceof RandomAccess) { for (int i=0; i<size; i++) list.set(i, obj);
} else {
ListIterator<? super T> itr = list.listIterator(); for (int i=0; i<size; i++) {
itr.next();
itr.set(obj);
}
}
}(6)copy()复制方法
/**
* 复制源列表的所有元素到目标列表, 如果src.size > dest.size 将抛出一个异常 如果src.size < dest.size
* dest中多出的元素将不受影响 同样是依次遍历赋值
*/public static <T> void copy(List<? super T> dest, List<? extends T> src) { int srcSize = src.size(); if (srcSize > dest.size()) throw new IndexOutOfBoundsException("Source does not fit in dest"); if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) { for (int i=0; i<srcSize; i++)
dest.set(i, src.get(i));
} else { // 一个链表一个线性表也可以用迭代器赋值
ListIterator<? super T> di=dest.listIterator();
ListIterator<? extends T> si=src.listIterator(); for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}(7)min()最小值法
/**
* 返回集合中的最小元素。前提是其中的元素都是可比的,即实现了Comparable接口
* 反正要依次遍历完所有元素,所以直接用了迭代器
*/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(); if (next.compareTo(candidate) < 0)
candidate = next;
} return candidate;
}/**
* 根据提供的比较器求最小元素
*/public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) { if (comp==null) return (T)min((Collection) coll);
Iterator<? extends T> i = coll.iterator();
T candidate = i.next(); while (i.hasNext()) {
T next = i.next(); if (comp.compare(next, candidate) < 0)
candidate = next;
} return candidate;
}(8)max()最大值方法
/**
*最大元素方法 同最小值
*/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(); if (next.compareTo(candidate) > 0)
candidate = next;
} return candidate;
}public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) { if (comp==null) return (T)max((Collection) coll);
Iterator<? extends T> i = coll.iterator();
T candidate = i.next(); while (i.hasNext()) {
T next = i.next(); if (comp.compare(next, candidate) > 0)
candidate = next;
} return candidate;
}(9)rotate()轮换方法
/**
* 旋转移位List中的元素通过指定的distance。每个元素移动后的位置为: (i +
* distance)%list.size.此方法不会改变列表的长度
* 比如,类表元素为: [t, a, n, k, s , w] 执行Collections.rotate(list, 2)或
* Collections.rotate(list, -4)后, list中的元素将变为 [s, w, t, a, n ,
* k]。可以这样理解:正数表示向后移,负数表示向前移
*/public static void rotate(List<?> list, int distance) { if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD)
rotate1(list, distance); else
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; for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
T displaced = list.get(cycleStart); int i = cycleStart; do {
i += distance; // 超出size就减去size
if (i >= size)
i -= size;
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; int mid = -distance % size; if (mid < 0)
mid += size; if (mid == 0) return; //这都可以,才发现
reverse(list.subList(0, mid));
reverse(list.subList(mid, size));
reverse(list);
}(10)replaceAll()替换,有改变返回true
/**
* 把指定集合中所有与oladVal相等的元素替换成newVal 只要list发生了改变就返回true
*/public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) {
boolean result = false; int size = list.size(); if (size < REPLACEALL_THRESHOLD || list instanceof RandomAccess) { 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 {
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;
}(11)int indexOfSubList 是否包含字符串
/**
*
* target是否是source的子集,如果是返回target第一个元素的索引, 否则返回-1。
* 其实这里和串的模式匹配差不多。这里使用的是基本的回溯法。
*
*/public static int indexOfSubList(List<?> source, List<?> target) { int sourceSize = source.size(); int targetSize = target.size(); int maxCandidate = sourceSize - targetSize; if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
(source instanceof RandomAccess&&target instanceof RandomAccess)) {
nextCand: 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))) continue nextCand; // Element mismatch, try next cand
return candidate; // All elements of candidate matched target
}
} else { // Iterator version of above algorithm
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())) { // Back up source iterator to next candidate
for (int j=0; j<i; j++)
si.previous(); continue nextCand;
}
} return candidate;
}
} return -1; // No candidate matched the target}static boolean eq(Object o1, Object o2) { return o1==null ? o2==null : o1.equals(o2);
}
作者:天一方蓝
链接:https://www.jianshu.com/p/46fdf4417666
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦