list集合获取指定元素,基于二分查找法

功能抄自JDK的Collections类,但源码不支持倒叙查找,做了一点点改动,使其支持。
见代码,注释很详细,就不啰嗦了。

private static final int BINARYSEARCH_THRESHOLD = 5000;
/**
     *
     * 功能描述:从指定list中,二分查找指定元素指定字段值,如在list<PrintBox> 中,查找字段FModel值为x的对象
     * ,list内的泛型元素须实现了Comparable接口并重写了compareTo方法
     * list须提前排序,正序倒序均可
     * 当list对象未实现RandomAccess接口或list.size()> 5000时,使用基于迭代器的二分法查找,反之,则基于索引的二分法查找。
     * 对于实现了RandomAccess接口的list,索引循环会比迭代器更快,如ArrayList
     * @Author 李
     * @MethodName getBinarySearch
     * @Date 17:47 2021/6/4
     * @param <T> list中的对象的类
     * @param list 被查找的list,建议用ArrayList,比较快
     * @param key 用于查找的对象,该对象中重写比较器时所用的用于比较的字段需有值
     * @return int 返回符合指定元素指定字段值的元素下标
     * @exception
     **/
    public static <T> int getBinarySearch(List<? extends Comparable<? super T>> list, T key) {
        if (list instanceof RandomAccess || list.size() < BINARYSEARCH_THRESHOLD) {
            return indexBinarySearch(list, key);
        } else {
            return iteratorBinarySearch(list, key);
        }
    }
    /**
     * 功能描述:基于迭代器的二分查找,list须提前排序,正序倒序均可
     * @param list
     * @param key  用于查找的对象,该对象中重写比较器时所用的用于比较的字段需有值
     * @return int
     * @throws
     * @Author 李
     * @MethodName getBinarySearch
     * @Date 11:37 2021/6/4
     **/
    private static <T> int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key) {
        int start = 0;
        int end = list.size() - 1;
        boolean flag = isReverse(list);
        ListIterator<? extends Comparable<? super T>> i = list.listIterator();
        while (start <= end) {
            int middle = (end + start) >>> 1;
            Comparable<? super T> midVal = getIterator(i, middle);
            int cmp = midVal.compareTo(key);
            if (flag){
                cmp *= (-1);
            }
            if (cmp < 0) {
                start = middle + 1;
            } else if (cmp > 0) {
                end = middle - 1;
            } else {
                return middle;
            }
        }
        return -(start + 1);
    }
    /**
     *
     * 功能描述:基于下标索引的二分查找,list须提前排序,正序倒序均可
     * @Author 李
     * @MethodName indexBinarySearch
     * @Date 17:45 2021/6/4
     * @param list
     * @param key 用于查找的对象,该对象中重写比较器时所用的用于比较的字段需有值
     * @return int
     * @exception
     **/
    private static <T> int indexBinarySearch(List<? extends Comparable<? super T>> list, T key) {
        int start = 0;
        int end = list.size() - 1;
        //第一个比最后一个大时,说明是倒序的。
        boolean flag = isReverse(list);
        while (start <= end){
            int middle = (end + start) >>> 1;
            Comparable<? super T> midVal = list.get(middle);
            int cmp = midVal.compareTo(key);
            if (flag){//倒序时,须反转正负
                cmp *= (-1);
            }
            if (cmp < 0) {
                start = middle + 1;
            } else if (cmp > 0) {
                end = middle - 1;
            } else {
                return middle;
            }
        }
        return -(start + 1);
    }
    /**
     *
     * 功能描述:判断一个list是否为倒序,须有序
     * @Author 李
     * @MethodName isReverse
     * @Date 19:06 2021/6/4
     * @param list
     * @return int
     * @exception
     **/
    @SuppressWarnings("unchecked")
    private static <T> Boolean isReverse(List<? extends Comparable<? super T>> list){
        if (CollectionUtils.isEmpty(list)){
            throw new MyException(10000,"列表为空");
        }
        int inter = list.get(0).compareTo((T)list.get(list.size()-1));
        return inter > 0;
    }
    /**
     *
     * 功能描述:从迭代器中获取指定对象
     * @Author 李
     * @MethodName get
     * @Date 10:37 2021/6/5
     * @param i 迭代器对象
     * @param index 索引
     * @return T
     * @exception
     **/
    private static <T> T getIterator(ListIterator<? extends T> i, int index) {
        T obj;
        int pos = i.nextIndex();
        if (pos <= index) {
            do {
                obj = i.next();
            } while (pos++ < index);
        } else {
            do {
                obj = i.previous();
            } while (--pos > index);
        }
        return obj;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值