二分查找(上)

有序数据集合的二分查找

  • 定义

    1. 二分查找针对的是一个有序的数据集合。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。
  • 时间复杂度分析:

    1. 数据大小n,每次查找,缩小1/2
    2. 最多查找k次。n/2k=1
    3. k=O(logn)
  • 应用场景

    1. 二分查找依赖顺序表结构(下标访问)
    2. 二分查找针对的是有序数据(不适用于排序变化的场景)
    3. 数据量太小不适合二分查找
    4. 数据量太大也不适合二分查找(需要连续内存)
  • 二分查找的循环实现

let arr = []
//随机数组元素
for (let i = 0; i < 40; i++) {
    arr.push(Math.round(Math.random() * 40))
}
//排序
arr.sort((a, b) => a - b)
console.log(String(arr))

//随机查找值
const value = Math.round(Math.random() * 40)
console.log(value, bsearch(arr, value))

function bsearch(arr, value) {
    //指针low从左向右,指针high从右向左
    let low = 0
    let high = arr.length
    /**
     * 实现
     * 1. low大于high时,跳出循环
     * 2. 取中间值,中间值等于value,则查找成功
     * 3. 中间值小于value,则low指向mid+1
     * 4. 中间值大于value,则high指向mid-1
     */
    /**
     * 注意
     * 1. low等于high,也是一种情况
     * 2. 避免溢出:mid = low + ((high-low)>>1)
     * 3. low和high更新,low = mid或high=mid,可能死循环
     */
    while (low <= high) {
        let mid = (low + high) >> 1
        if (arr[mid] == value) {
            return mid
        } else if (arr[mid] < value) {
            low = mid + 1
        } else {
            high = mid - 1
        }
    }
    return -1
}
  • 二分查找的递归实现
let arr = []
//随机数组元素
let num = 10
for (let i = 0; i < num; i++) {
    arr.push(Math.round(Math.random() * num))
}
//排序
arr.sort((a, b) => a - b)
console.log(String(arr))

//随机查找值
const value = Math.round(Math.random() * num)
console.log(value, bsearch(arr, 0, arr.length, value))

function bsearch(arr, low, high, value) {
    /**
     * 递归公式:判断中间值
     *      1. 等于value则返回
     *      2. 小于value则向右查找
     *      3. 大于value则向左查找
     * 终止条件:low > high或已找到
     */
    if (low > high) return -1
    //优先级:+ 大于 >>
    let mid = low + ((high - low) >> 1)
    if (arr[mid] == value) {
        return mid
    } else if (arr[mid] < value) {
        return bsearch(arr, mid + 1, high, value)
    } else {
        return bsearch(arr, low, mid - 1, value)
    }
}
  • 求一个数的平方根


//平方根位数
var weishu = 6
//测试数据
for (let i = 0; i < 1000; i++) {
    let data = Math.random() * 100
    let diff = Math.pow(10, weishu) * (fun(data) - Math.sqrt(data))
    console.log(fun(data), diff <= 0 && diff > -1)
}


function fun(num) {
    //返回结果
    let res
    if (num == 1) {
        res = 1
    } else {
        res = 0
        for (let i = 0; i <= weishu; i++) {
            recursive(Math.pow(10, -1 * i))
        }
        //舍入误差解决
        let expend = Math.pow(10, weishu)
        res = Math.round(res * expend) / expend
    }

    //小数点后weishu位
    return res.toFixed(weishu)
    /**
     *  0. 循环,每次cur增加digit
     *  1. 退出循环,cur方 <= num < (cur + digit*n)方,查询成功
     */
    function recursive(digit) {
        let end = 10
        //整数部分
        if (digit == 1) {
            end = num
        }
        for (let i = 0; i < end; i++) {
            if (num >= powValue(res + i * digit) && num < powValue(res + (i + 1) * digit)) {
                res = res + i * digit
                return
            }
        }
    }

    function powValue(value, param = 2) {
        return Math.pow(value, param)
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值