二分查找

20 阅读2分钟

二分查找

二分查找是一种基于分治策略的高效搜索算法

利用数据的有序性,每轮缩小一半搜索范围,直到找到目标或者搜索区间为空为止


例:给定一个长度为 的数组 nums ,元素按从小到大的顺序排列且不重复。请查找并返回元素 target 在该数组中的索引。若数组不包含该元素,则返回-1。

我们先初始化指针i=0和j=n-1,分别指向数组的首元素和尾元素,代表搜索区间为[0,n-1]

接下来,循环执行以下两步

  • 计算中点索引m=[(i+j)/2],若为小数则向下取整

  • 判断nums[m]和target的大小关系

    • nums[m] < target 时,说明 target 在区间[m+1,j]中,因此执行i=m+1。
    • nums[m] > target 时,说明 target 在区间[0,m-1]中,因此执行j=m-1。
    • nums[m] = target 时,说明找到 target ,因此返回索引m。
  • 如果数组不包含目标元素,搜索区间最终会缩小为空。返回-1

注意:由于i和j都是 int 类型,因此 可能会超出 int 类型的取值范围。为了避免大数越界,我们通常采用公式m=[i+(j-i)/2]来计算中点。

/*二分查找(双闭区间)*/
func binarySearch(nums []int,target int) int{
    //初始化双闭区间[0, n-1]
    i := 0
    j := len(nums)-1
    //循环,当搜索空间为空时跳出  当i>j时为空
    for i <= j{
        m := i + (j-i)/2    //中间索引
        if nums[m] < target{    //此时target在中间索引的右边
            i = m + 1
        }else if nums[m] > target{  //此时target在中间索引的左边
            j = m-1
        }else { //找到目标元素
            return m
        }
    }
    //循环结束意味着区间搜索完毕,没有找到元素,返回-1
    return -1
}

除了双闭区间,常见的还有左闭右开区间,即[0,n),左边界包含自身,右边界不包含自身。在这种情况下,区间[i,j)在i=j时为空

/*二分查找(左闭右开区间)*/
func binarySearch(nums []int,target int) int{
    //初始化双闭区间[0, n-1]
    i := 0
    j := len(nums)
    //循环,当搜索空间为空时跳出  当i=j时为空
    for i < j{
        m := i + (j-i)/2    //中间索引
        if nums[m] < target{    //此时target在中间索引的右边
            i = m + 1
        }else if nums[m] > target{  //此时target在中间索引的左边
            j = m
        }else { //找到目标元素
            return m
        }
    }
    //循环结束意味着区间搜索完毕,没有找到元素,返回-1
    return -1
}