二分查找是用来查找有序数组中的某个元素a,在元素过多时可以大量减少计算的时间。如:若数组中的元素有22亿个,直接折半变为11亿了,查找范围大大减少。
使用条件:有序数组
内部逻辑:
找数组下标的中间值i(因为下标的值是固定的数字),将其对应的元素arr[i]与a比较,若arr[i]<a,可去掉arr[i]左边的所有数。
以arr[9] = {1,2,3,4,5,6,7,8,9}为例,查找其中的元素8,即a = 8;
元素 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
下标0与8的中值为 (0+8)/2 = 4,则arr[4] = 5; 因为 5<8,那么去除5左边的所有数,只比较其右边的数与8的关系。
元素 | 6 | 7 | 8 | 9 |
下标 | 5 | 6 | 7 | 8 |
继续求下标5和8中值 (5+8)/2 = 6,则arr[6] = 7; 因为 7<8,那么去除7左边的所有数,只比较其右边的数与8的关系。
以此类推……直到查找到元素8,输出。
代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
//二分查找(折半查找)
//查找数组中的一个数字
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int a = 8;//查找的数为8
int sz = sizeof(arr) / sizeof(arr[0]);//数组中的元素个数
int left = 0;
int right = sz - 1;
while (left <= right)
{
int avg = (left + right) / 2;//下标中值
if (arr[avg] < a)
{
left = avg + 1;
}
else if (arr[avg] > a)
{
right = avg - 1;
}
else
{
printf("找到了,下标为%d", avg);
break;
}
}
return 0;
}
根据代码定义的变量名,上面的解释可改为
下标0(left)与8 (right) 的中值 (avg) 为 (0+8)/2 = 4,则arr[4] = 5; 因为 5<8,那么去除5左边的所有数,只比较其右边的数与8的关系。
继续求下标5 (avg+1)和8 (right) 中值为 (5+8)/2 = 6,则arr[6] = 7; 因为 7<8,那么去除7左边的所有数,只比较其右边的数与8的关系。
从 left 到 right 为比较的范围,随每一次的元素折半,范围也会发生变化。如果是左边被去掉,那么折半后的范围:左区间变为 avg+1,右区间范围不变。