有序数组的查找

有序数组的查找

题目描述

给定一个排好序的数组,查找某个数是否在这个数组中,请编程实现。

分析与解法

一看到数组本身已经有序,直观的反应可能是用二分查找算法,毕竟二分查找算法的适用条件就是要求数组是有序的。那么什么是二分查找呢?

二分查找可以解决已排序数组的查找的问题,即只要数组中包含 T(要查找的值),那么通过不断缩小包含T的数据范围,就可以最终找到要找的数T。其算法流程如下。

1)一开始,数据范围覆盖整个数组。

2)将数组的中间项与T进行比较,如果T比数组的中间项小,则到数组的前半部分继续查找,反之,则到数组的后半部分继续查找。

3)这样,每次查找都可以排除一半元素,相当于范围缩小一半。这样反复比较,反复缩小范围,最终会在数组中找到T,或者确定T不在此数组中。

对于包含n个元素的数组,整个查找过程大约要经过log n次比较。

此时,可能有读者心里想,不就二分查找嘛,太简单了。但是,《编程珠玑》的作者Jon Bentley曾在贝尔实验室做过一个实验,即给一些专业的程序员几个小时的时间,用任何一种语言编写二分查找的程序(写高级伪代码也可以),结果参与编写的一百多个人中,90%的程序员写的程序中有bug(没发现bug的代码不代表就正确)。也就是说,在足够的时间内,只有大约10%的专业程序员可以把二分查找写对。此外,高德纳在《计算机程序设计的艺术 第3卷:排序和查找》的6.2.1节的“历史与参考文献”中指出,虽然早在1946年就有人将二分查找的方法公诸于世,但直到1962年才有人写出没有bug的二分查找程序。

实际上,要想编写出正确的二分查找程序,必须注意到两点:一点是判断循环体是否终止的语句的编写,另外一点是边界值leftright和区间值这三个地方要保持一致。

关于第二点再详细说明一下。比如,如果令right=n−1,则while循环的循环条件为left <= right,从而更新右边界位置的时候为right=middle−1;而如果令right=n,则while循环的循环条件为left < right,从而更新右边界位置的时候为right=middle。同时,middle的计算不能写在while循环外,否则无法得到更新。

以下是一份参考实现:

int BinarySearch(int array[], int n, int value)
{
         int left = 0;
         int right = n - 1;
         // 如果上面这句是int right = n的话,则下面有两处地方需要修改,以保证一一对应:
         // 1. 循环的条件是while(left < right);
         // 2. 循环内,当array[middle] > value的时候,right = mid。
 
         while (left <= right)  // 循环条件,适时而变
         {
                 // 求中间位置,使用移位的方法是为了防止溢出,同时也更高效。注意,每次循环都需要更新
                 int middle = left + ((right - left) >> 1);
                 if (array[middle] > value)
                 {
                         right = middle - 1;  // right赋值,适时而变
                 }
                 else if (array[middle] < value)
                 {
                         left = middle + 1;
                 }
                 else
                 {
                         // 可能会有读者认为刚开始时就要判断相等,但其实无关紧要,毕竟数组中不相等的情况更多
                         return middle;
                 }
         }
         return -1;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值