算法:二分查找

一、二分查找算法

1、二分查找

package Search_zhu;

/*
    二分查找:依赖的是有序数组
    时间复杂度为O(logn)
 */
public class MidSearch {
    public static int midsearch(int[] a,int value){
        int begin = 0;
        int end = a.length - 1;

        while (begin <= end){
            int mid = 2 * begin + (end - begin) / 2;
            if (a[mid] > value){
                end = mid - 1;
            }else if(a[mid] < value){
                begin = mid + 1;
            }else{
                return mid;
            }
        }

        return -1;
    }

    public static void main(String[] args) {
        int[] a = new int[]{3,5,9,12,39,50};
        System.out.println(midsearch(a,9));
    }
}

2、递归实现二分查找

package Search_zhu;

/*
    递归实现二分查找:替换for循环
 */

public class DgMidSearch {
    public static int midsearch(int[] a,int n,int value){
        return dgmidsearch(a,0,n-1,value);
    }

    public static int dgmidsearch(int[] a,int begin,int end,int value){
        if (begin > end) return -1;

        int mid = begin + (end - begin) / 2;
        if (a[mid] == value){
            return mid;
        }else if (a[mid] > value){
            return dgmidsearch(a,begin,mid - 1,value);
        }else{
            return dgmidsearch(a,mid + 1,end,value);
        }
    }

    public static void main(String[] args) {
        int[] a = new int[]{2,6,9,12,25,35,98};
        System.out.println(midsearch(a,7,12));
    }
}

3、查找第一个等于给定值的值的下标

package Search_zhu;

/*
    二分查找:查找第一个值等于给定值的下标
 */

public class MidSearch1 {
    public static int midsearch1(int[] a,int value){
        int begin = 0;
        int end = a.length - 1;

        while (begin <= end){
            int mid =  begin + (end - begin) / 2;
            if (a[mid] > value){
                end = mid - 1;
            }else if (a[mid] < value){
                begin = mid + 1;
            }else{
                //若mid是第一个或mid的前一个不等于value,直接返回mid;否则end往前推
                if ((mid == 0) || a[mid - 1] != value)  return mid;
                else end = mid - 1;
            }
        }

        return -1;
    }

    public static void main(String[] args) {
        int[] a = new int[]{2,5,9,23,23,36,58};
        System.out.println(midsearch1(a,23));
    }
}

4、查找最后一个等于给定值的值的下标

package Search_zhu;

/*
    二分查找:找到最后一个值等于给定值的下标
 */
public class MidSearch2 {
    public static int midsearch2(int[] a,int value){
        int begin = 0;
        int end = a.length - 1;

        while (begin <= end){
            int mid = begin + (end - begin) / 2;
            if (a[mid] > value){
                end = mid - 1;
            }else if(a[mid] < value){
                begin = mid + 1;
            }else{
                if (mid == end || a[mid + 1] != value){
                    return mid;
                }else{
                    begin = mid + 1;
                }
            }
        }

        return -1;
    }

    public static void main(String[] args) {
        int[] a = new int[]{2,5,23,23,23,36,58};
        System.out.println(midsearch2(a,23));
    }
}

5、查找第一个大于等于给定值的值的下标

package Search_zhu;

/*
    二分查找:查找第一个大于等于给定值的元素
 */
public class MidSearch3 {
    public static int midsearch3(int[] a,int value){
        int begin = 0;
        int end = a.length - 1;

        while (begin <= end){
            int mid = begin + (end - begin) / 2;
            if (a[mid] >= value){
                if (mid == 0 || a[mid - 1] < value ) return mid;
                else end = mid - 1;
            }else{
                begin = mid + 1;
            }
        }

        return -1;
    }

    public static void main(String[] args) {
        int[] a = new int[]{2,5,23,23,23,36,58};
        System.out.println(midsearch3(a,5));
    }
}

6、查找最后一个小于等于给定值的值的下标

package Search_zhu;

/*
    二分查找:查找最后一个小于等于给定值的下标
 */
public class MidSearch4 {
    public static int midsearch4(int[] a,int value){
        int begin = 0;
        int end = a.length - 1;

        while (begin <= end){
            int mid = begin + (end - begin) / 2;
            if (a[mid] > value){
                end = mid - 1;
            }else{
                if (mid == end - 1 || a[mid + 1] > value) return mid;
                else begin = mid + 1;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] a = new int[]{2,5,23,23,23,36,58};
        System.out.println(midsearch4(a,25));
    }
}

二、二分查找的局限性

  • 二分查找依赖的是顺序表结构,就是数组。原因是二分查找需要依赖数组根据下标随机访问的特性,如果是链表的话,找到中间节点是需要遍历链表的一半
  • 二分查找依赖的是有序数据,二分查找依赖的是有序数组,如果没有序,需要先排序,堆排、快排、归并排的时间复杂度为O(nlogn),如果针对的是静态数组,可以实现一次排序,多次二分查找;如果是动态数组,不断插入或删除,数据插入和删除都要先进行排序,这时排序的成本就比较高,针对这种动态集合,更适合用二叉树来进行查找
  • 数据量太少不适合用二分查找,在这种情况下,二分查找和顺序遍历的时间差不多,但如果比较操作非常耗时,比如数组中存储的是字符串,这时还是推荐用二分查找*
  • 数据量太大也不适合用二分查找,因为二分查找依赖的是数组,数组必须要有连续的内存空间,对内存的要求比较严苛,在资源不足的情况下,使用二分查找是不合适的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我爱夜来香A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值