在数字化转型中,选择合适的跨平台开发框架不仅能提高效率,还有助于确保数据安全与合规性。
713
2022-08-24
有序数组的查找
有序数组的查找
题目描述
给定一个排好序的数组,查找某个数是否在这个数组中,请编程实现。
分析与解法
一看到数组本身已经有序,直观的反应可能是用二分查找算法,毕竟二分查找算法的适用条件就是要求数组是有序的。那么什么是二分查找呢?
二分查找可以解决已排序数组的查找的问题,即只要数组中包含 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的二分查找程序。
实际上,要想编写出正确的二分查找程序,必须注意到两点:一点是判断循环体是否终止的语句的编写,另外一点是边界值left、right和区间值这三个地方要保持一致。
关于第二点再详细说明一下。比如,如果令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;}
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~