继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

当我们在聊Collections

慕标5832272
关注TA
已关注
手记 1254
粉丝 231
获赞 1002

一丶概述

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


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP