• 算法学习:二分查找


    一、二分查找算法

    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));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    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));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    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));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    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));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    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));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    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));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    二、二分查找的局限性

    • 二分查找依赖的是顺序表结构,就是数组。原因是二分查找需要依赖数组根据下标随机访问的特性,如果是链表的话,找到中间节点是需要遍历链表的一半
    • 二分查找依赖的是有序数据,二分查找依赖的是有序数组,如果没有序,需要先排序,堆排、快排、归并排的时间复杂度为O(nlogn),如果针对的是静态数组,可以实现一次排序,多次二分查找;如果是动态数组,不断插入或删除,数据插入和删除都要先进行排序,这时排序的成本就比较高,针对这种动态集合,更适合用二叉树来进行查找
    • 数据量太少不适合用二分查找,在这种情况下,二分查找和顺序遍历的时间差不多,但如果比较操作非常耗时,比如数组中存储的是字符串,这时还是推荐用二分查找*
    • 数据量太大也不适合用二分查找,因为二分查找依赖的是数组,数组必须要有连续的内存空间,对内存的要求比较严苛,在资源不足的情况下,使用二分查找是不合适的
  • 相关阅读:
    ​@Cacheable 注解​
    保研专业课参考
    PCB设计中的邮票孔封装如何制作?
    千万别再一个人闷头做事了
    淘宝开放平台官方API接口获取淘宝app商品详情原数据,产品优惠券信息, 产品详情信息示例
    鸢尾花分类模型demo-恢复、部署、保存
    软件设计开发笔记3:基于QT的Modbus RTU主站
    代码整洁之道-读书笔记之格式
    牛客网经典Java面试常见题
    Vue—大文件分片上传
  • 原文地址:https://blog.csdn.net/nzbing/article/details/125529073