数据结构与算法-----7.二分查找:

1.概念:二分查找也称为 “折半查找”,采用的是二分思想,每次可以将数据查询的范围缩小为原来的一半,所以它的效率非常高。

同时二分查找针对的也是有序的数据集合,它的时间复杂度为O(logn)。

2.O(logn)是一个非常恐怖的数量级,即使n非常大,但是对应的logn的结果也是非常的小。2^32次方大约等于42亿,但是我们从42亿个数据中利用二分查找来搜索数据,也就查找32次就够了。

3.O(logn)有时候甚至比常量及的时间复杂度O(1)还要高效,因为再计算时间复杂度时,我们会忽略掉低阶,常数等,所以O(1)可能指O(100),O(10000),它有时比O(logn)效率低。

4.简单的二分查找实现:

/* 简单的二分查找算法:使用二分查找的前提:序列必须是有序的*/
public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,0,7,6,54,3,7,34,36,98};
        QuickSort sort = new QuickSort();
        sort.quickSrotInternally(arr,0,arr.length-1);
        BinarySearch binarySearch = new BinarySearch();
        int pivot = binarySearch.binarySearch(arr,98);
        System.out.println(pivot);
    }
    public int binarySearch(int[] arr,int target) {
        if(arr == null) return -1;
        int low = 0;
        int high = arr.length - 1;
        /*一定是low <= high , 因为如果是low<high,那么可能某一些元素会搜索不到*/
        while (low <= high) {
            /*如果是int pivot = (low + high) / 2; 其实是不准确的。因为如果low和high是特别大的
            * 32位的数据,那么low+high有可能会出现溢出的问题。
            * 如果需要将性能优化到极致,那么可以low + ((high-low)>>1); 因为移位运算比除法更快*/
            int pivot = low + (high-low)/2;
            if (target == arr[pivot]) {
                return arr[pivot];
            } else if (target < arr[pivot]) {
                /*这里一定是pivot-1或者pivot+1,如果要是写成hight=pivot,那么某些情况下可能会出现死循环。*/
                high = pivot - 1;
            }else {
                low = pivot + 1;
            }
        }
        return -2;
    }
}

5.二分查找的局限性:

(1)二分查找依赖的是顺序表结构,简单点来说就是数组,即使链表也是顺序表结构,但是二分查找算法需要利用下标随机访问元素,链表不支持随机访问,所以不可以。

(2)需要进行二分查找的数据,必须是有序数据,如果数据杂乱无章,那么需要先排好顺序。

(3)数据量太小的不适合二分查找:因为数据量太小,利用顺序遍历就可以了,二分查找也显现不出来优势。但是如果数据之间的比较操作比较耗时,那么尽管数据量非常小,也建议使用二分查找。例如:在String类型的数组中查找某一个字符串,每一个字符串的长度非常长,这时使用遍历逐一比较非常耗时。

(4)数据量特别大也不适合二分查找:因为二分查找依赖数组,数组在内存中需要连续的存储空间,如果待查找的数据大小为1GB,那么找到一块连续的1GB空间有些吃力。

6.二分查找的变体:

(1)在序列中查找第一个与目标值相等的元素:

/*二分查找变体一:查找第一个等于给定值的元素。*/
public int bSearchFirst(int[] arr,int target) {
    if(arr == null) return -1;
    int low = 0;
    int high = arr.length-1;
    while (low <= high) {
        int mid = low + ((high-low)>>1);
        /*如果中间值大于target,那么要查找的值一定在左边*/
        if(arr[mid] > target) {
            high = mid - 1;
        }else if(arr[mid] < target) {/*如果中间值小于target值,那么要查找的值一定在右边*/
            low = mid + 1;
        }else {
            /*如果当前数组下标为0,或者当前元素的前一个元素,比target值小,那么当前值就是第一个要找的值*/
           if(mid == 0 || arr[mid - 1] < target) {
               System.out.println("第一个等于目标值的索引:"+mid);
               return arr[mid];
           }else {
               high = mid - 1;
           }
        }
    }
    return -2;
}

(2)在序列中查找第一个大于等于给定值的元素:

/*变体二:查找第一个大于等于给定值的元素*/
public int bSearchLast(int[] arr,int target) {
    if(arr == null) return -1;
    int low = 0;
    int high = arr.length - 1;
    while (low <= high) {
        int mid= low + ((high-low) >> 1);
        if(arr[mid] < target) {
            low = mid + 1;
        }else {
/*如果当前元素下标为0,或者当前元素的前一个元素值小于目标元素,那么当前元素为要查找的值*/
            if(mid == 0 || arr[mid - 1] < target) {
                System.out.println("第一个大于等于给定元素的下标:"+mid);
                return arr[mid];
            }else {
                high = mid - 1;
            }
        }
    }
    return -2;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值