查找有序数组——二分查找

157 阅读4分钟

这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战

查找有序数组

常规数组的查找方式:从左至右,逐个格子检查,直至找到。这种方式称为线性查找。

接下来看看有序数组的线性查找跟常规数组有何不同。

设一个常规数组[17,3,75,202,80],如果想在里面查找22(其实并不存在),那你就得逐个元素去检查,因为22可能在任何一个位置上。要想在到达末尾之前结束检查,那么所找的值必须在末尾之前出现。

然而对于有序数组来说,即便它不包含要找的值,我们也可以提早停止查找。假设要在有序数组[3,17,75,80,202]里查找22,我们可以在查到75的时候就结束,因为22不可能出现在75的右边。 因此,有序数组的线性查找大多数情况下都会快于常规数组。除非要找的值是最后那个,或者比最后的值还大,那就只能一直查到最后了。

只看到这里的话,可能你还是不会觉得两种数组在性能上有什么巨大区别。

这是因为我们还没释放算法的潜能。这是接下来就要做的。

至今我们提到的查找有序数组的方法就只有线性查找。但其实,线性查找只不过是查找算法的其中一种而已。这种逐个格子检查直至找到为止的过程,并不是查找的唯一途径。

有序数组相比常规数组的一大优势就是它可以使用另一种查找算法。此种算法名为二分查找,它比线性查找要快得多

二分查找

你小时候或许玩过这样一种猜谜游戏(或者现在跟你的小孩玩过):我心里想着一个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步,但稍后你就会见识到二分查找的强大。