如何写出正确的二分查找算法?
二分查找算法很经典,但不少人一看就会一写就废(包括我),关键问题出现在对以下三个细节没有理解正确。
注意点1:左闭右闭还是左闭右开?
给定数组长度n,high到底等于n还是n-1?
两种写法都是可以的,但选择其中一种后,会衍生出两种不同版本的二分查找写法,具体的我们在下面推导。
注意点2:等于还是小于等于?
假设选择左闭右闭,那么 low = high 就是有意义的,怎么理解?假设数组长度为 1,你在 while 条件里写了 low < high,则当 low = high = 0 时,将会跳过循环,但是数组里的这个数字有可能就是我们要找的。所以,当选择左闭右闭时,while条件必须是 low <= high。
假设选择左闭右开,那么 low = high 没有意义,low 指向实际的值,而 high 可能指向越界的值(初始化时 high = len)。所以while条件时 low < high。
注意点3:mid加减1还是mid?
选择左闭右闭时,假设 mid 值指向的元素比目标元素大,我们要去左区间寻找,因为 while 循环条件是左闭右闭,所以更新的 high 必须是未被搜索过的下标,由于已经确定 mid 不是我们要的,所以更新时要将 mid 进行减1操作。同理,当更新 low 值时需要加1 操作。
选择左闭右开时,假设 mid 值指向的元素比目标元素大,我们要去左区间寻找,因为 while 循环条件是左闭右开,所以更新的 high 值必须是边界,不能是未被搜索过的下标。由于 middle - 1 没有被搜索过,而 middle 已经被排除了,所以 high 更新为被排除的 mid 下标。
总结
左闭右闭,low <= high,更新时加减1。
左闭右开,low < high,更新时不变。