在二分查找当中,为什么我们使用 `mid = ((right - left) >> 1) + left`?

在二分查找等算法中,我们经常需要计算区间的中间位置,一般可以使用 mid = (left + right) / 2 这种常规写法,但在一些场景下会采用 mid = ((right - left) >> 1) + left 这样的写法,以下是具体原因:

避免整数溢出

在许多编程语言里,整数类型的取值范围是有限的。当 leftright 都非常大时,使用 (left + right) / 2 可能会导致整数溢出。

例如,在 JavaScript 中,Number 类型是双精度 64 位浮点数,虽然能表示很大的数,但如果 leftright 足够大,它们相加的结果可能会超出安全整数范围(Number.MAX_SAFE_INTEGER,即 2**53 - 1),从而造成精度丢失。

以下是一个示例代码,展示了溢出情况:

let left = Number.MAX_SAFE_INTEGER - 1;
let right = Number.MAX_SAFE_INTEGER;
// 一般写法会发生溢出问题
let mid1 = (left + right) / 2; 
// 但是换成这个写法就不会溢出
let mid2 = ((right - left) >> 1) + left; 
console.log(mid1); 
console.log(mid2); 

在上述代码中,(left + right) / 2 可能会得到错误的结果,而 ((right - left) >> 1) + left 能避免这个问题。因为 right - left 的值通常不会很大,不会超出整数表示范围。

位运算的性能优势

>> 是右移运算符,(right - left) >> 1 等价于 Math.floor((right - left) / 2)位运算在计算机底层的执行速度通常比除法运算要快因为它直接操作二进制位,不需要进行复杂的数学运算。所以使用 ((right - left) >> 1) + left 不仅能避免溢出,还可能在性能上有一定提升。

综上所述,mid = ((right - left) >> 1) + left 这种写法既可以避免整数溢出问题,又可能提高代码的执行效率,因此在实际编程中被广泛应用于二分查找当中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值