你小时候或许玩过这样一种猜谜游戏:我心里想着一个1到100之间的数字,在你猜出它之前,我会提示你的答案应该大一点还是小一点。
你应该凭直觉就知道这个游戏的策略。一开始你会先猜处于中间的50,而不是1。为什么?因为不管我接下来告诉你更大或是更小,你都能排除掉一半的错误答案!
如果你说50,然后我提示要再大一点,那么你应该会选75,以排除掉剩余数字的一半。如果在75之后我告诉你要小一点,你就会选62或63。总之,一直都猜中间值,就能不断地缩小一半的范围。
下面来演示这个过程,但仅以1到10为例。
这就是二分查找的通俗描述。
有序数组相比常规数组的一大优势就是它除了可以用线性查找,还可以用二分查找。常规数组因为无序,所以不可能运用二分查找。
为了看出它的实际效果,假设有一个包含9个元素的有序数组。计算机不知道每个格子的值,如下图所示。
然后,用二分查找来找出7,过程如下。
第1步:检查正中间的格子。因为数组的长度是已知的,将长度除以2,我们就可以跳到确切的内存地址上,然后检查其值。
值为9,可推测出7应该在其左边的某个格子里。而且,这下我们也排除了一半的格子,即9右边的那些(以及9本身)。
第2步:检查9左边的那些格子的最中间那个。因为这里最中间有两个,我们就随便挑了左边的。
它的值为4,那么7就在它的右边了。由此4左边的格子也就排除了。
第3步:还剩两个格子里可能有7。我们随便挑个左边的。
第4步:就剩一个了。(如果还没有,那就说明这个有序数组里真的没有7。)
终于找到7了,总共4步。这个有序数组要是用线性查找会是4步。
以下是二分查找的Ruby实现。