二分查找法详解

1.二分查找

问题概述:在一个有序的数组内,例如{5,13,19,21,37,56,64,75,80,88,92}中,查找出指定元素。如果存在范围该元素的索引,否则返回null.

例如:
在这里插入图片描述

算法描述

  • 前提条件:数组为一个有序数组a[],数组长度为n,目标元素为target。

  • 令low指向数组的开头索引,high指向数组结尾索引,mid指向数组中间索引.(floor表示向下取整)
    l o w = 0 ; h i g h = n − 1 ; m i d = f l o o r ( ( l o w + h i g h ) / 2 ) low=0;high=n-1;mid=floor((low+high)/2) low=0;high=n1;mid=floor((low+high)/2)

  • 如果target>a[mid],low=mid+1,即目标元素在索引mid和high之间。

  • 如果target<a[mid],high=mid-1,即目标元素在索引low和mid之间。

  • 重复上述target和a[mid]的比较,利用二分法不断缩小目标元素所在区域,从而找到目标元素。即a[mid]=target.

  • 如果low>high,即目标元素不在这个数组中,因为遍历结束也没有找到。

算法实现

非递归
/**
 * @BelongsProject: algorithm
 * @BelongsPackage: com.victorzl.algorithm
 * @Author: VictorZl
 * @CreateTime: 2023-10-24  21:14
 * @Description: 二分查找法
 * @Version: 1.0
 */
public class BinarySearch {
    /**
     *
     * @param a
     * @param target
     * @return 如果找到目标元素返回目标元素所在数组的索引,否则返回-1
     */
    public static int binarySearch(int[] a,int target)
    {
        int low=0,high=a.length;                        //设置初始状态的指针
        while (low<=high)                               //如果low<high,说明查找未结束
        {
            int mid=(low+high)/2;                       //根据low和high指针不断更新中间索引指针
            if(target<a[mid])                           //目标元素在左区域
            {
                high=mid-1;
            }
            else if (target>a[mid])                     //目标元素在右区域
            {
                low=mid+1;
            }
            else {
                return mid;                             //找到目标值
            }
        }
        return -1;
    }
}

问题:

int(整型)的数据范围:-2147483648——2147483647;

int a = 2147483647;//定义一个int型变量a的值为int型能够保存的最高值

a+1=-2147483648 //由于java中32位中最高位表示正负

在计算机中,整数通常使用补码表示。正数的补码就是其本身。

因此,2147483647的二进制补码表示为0111 1111 1111 1111 1111 1111 1111 1111。

而1的二进制补码表示为0000 0000 0000 0000 0000 0000 0000 0001。

将这两个补码相加,得到1000 0000 0000 0000 0000 0000 0000 0000。这个结果的最高位是1,表示负数。根据补码的转换规则,我们需要将这个补码转换回原码。

转换过程如下:

首位符号位不变,其余位置取反:1111 1111 1111 1111 1111 1111 1111 1111。
末尾加1,得到1 0000 0000 0000 0000 0000 0000 0000 0000。
舍弃溢出的部分:0000 0000 0000 0000 0000 0000 0000 0000。

对于int类型的范围,当发生溢出时,它会循环回到最小值。因此,2147483647 + 1的结果是-2147483648。

在这里插入图片描述

所以在上述算法中int mid=(low+high)/2,可能会出现负数,从而出现问题;

改进:利用二进制向右移位的性质,相当于除以2,即使是溢出为负数,但是他的二进制不会变动,右移后最高位变为0,变为正数,达到除以2的效果,所以不受影响。

/**
 * @BelongsProject: algorithm
 * @BelongsPackage: com.victorzl.algorithm
 * @Author: VictorZl
 * @CreateTime: 2023-10-24  21:14
 * @Description: 二分查找法改进
 * @Version: 1.0
 */
public class BinarySearch {
    /**
     *
     * @param a
     * @param target
     * @return 如果找到目标元素返回目标元素所在数组的索引,否则返回-1
     */
    public static int binarySearch(int[] a,int target)
    {
        int low=0,high=a.length;                        //设置初始状态的指针
        while (low<=high)                               //如果low<high,说明查找未结束
        {
            int mid=(low+high)>>>1;                     //根据low和high指针不断更新中间索引指针
            if(target<a[mid])                           //目标元素在左区域
            {
                high=mid-1;
            }
            else if (target>a[mid])                     //目标元素在右区域
            {
                low=mid+1;
            }
            else {
                return mid;                             //找到目标值
            }
        }
        return -1;
    }
}
递归
package com.victorzl.algorithm;

/**
 * @BelongsProject: algorithm
 * @BelongsPackage: com.victorzl.algorithm
 * @Author: VictorZl
 * @CreateTime: 2023-10-26  09:34
 * @Description: 递归二分查找法
 * @Version: 1.0
 */
public class RecursionBinarySearch {
    public static int recursionBinarySearch(int[] a,int low,int high, int target) {
        if (low <= high) {
            int mid = (low + high)>>>1;     
            if (a[mid] == target) {
                return mid;
            } else if (a[mid] > target) {
                return recursionBinarySearch(a, low, mid - 1, target);
            } else {
                return recursionBinarySearch(a, mid - 1, high, target);
            }
        }
        return  -1;
    }
}

时间复杂度分析

在二分法中,每次将待查找区间缩小一半,因此需要进行log n次查找才能找到目标元素。具体来说,假设待查找区间大小为n,每次查找后区间大小减半,直到区间大小为1,需要进行k次查找才能找到目标元素,即:

n/2^k = 1 解得k=log n。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Victor ZL

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

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

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

打赏作者

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

抵扣说明:

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

余额充值