假设有题目是:在一个有序的数组中查找具体的某个数字。我想大部分的人都会写出我下面的代码:
这个方法虽然可行,但是它找的太慢了。想象一下,数组如果有n个元素,最坏的情况下要找n次,但这个题目中有个小的细节,在有序数组中查找。
而有序就给我们更多的可能性,举个简单的例子,假如玩一个游戏叫猜数字,规则是从1~100中猜一个数,而大部分人肯定都会从中间的数开始猜(50),假如答案是75,我就会说猜小了,接下来玩家肯定就会从50~100来猜一个数,这样是不是猜起来更快些呢?
如上图,假设要在这有序的数组中找 3,那我们怎么样找的更快些呢?刚刚说过了,肯定要找中间元素,那如何找中间元素呢?我们可以定义一个左下标(left)和右下标(right),则中间值(mid)就等于(left+right)/2=4,而此时mid的值4对应的数组元素为5,5和我要找的3是不是太大了,这时显然5的右边不会有3。
如上图,所以接下来中间值要减1来作为新的右下标(3),left不变,继续计算它新的中间值mid=(0+3)/2=1,现在下标1对应数组元素为2,而2对于我要找的3太小了。
如上图,所以再接下来mid要加1等于2做为新的左下标,右下标不变还是3,则继续计算它新的中间值mid=(2+3)/2=2,而此时的下标2刚刚好就是我要找的数组元素3。
这样每查找一次就砍掉一半(折半查找/二分查找),是不是非常快而且效率也非常高。下面是代码实现:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int n = 3; //比方查找3
int left = 0; //对应右下标
int right = 9; //对应左下标
int flag = 0;
while (left<=right) //left<=right还能被查找
{
int mid = (left + right) / 2; //求出中间元素的下标
if (arr[mid] > n)
{
right = mid - 1;
}
else if (arr[mid] < n)
{
left = mid + 1;
}
else //(arr[mid]==n)
{
printf("找到了,下标是:%d\n", mid);
flag = 1;
break;//找到就终止循环
}
}
if (flag == 0)
printf("找不到\n");
return 0;
}
在vs上的结果:
这种方法效率高,但是前提条件非常苛刻,数据必须是有序的。
看到这里你了解二分查找法了吗