二分查找的核心思想是在有序的序列中,每次与中间元素比较,若比中间元素大,则查找元素出现在右半部分,反之则出现在左半部分,然后对改新的区间进行如上操作。直到找到对应元素,或者low > high 递归终止条件。时间复杂度为O(logn)
局限性
- 需要有序数据,对动态数据集不怎么使用,性能耗费高。适用于插入、删除操作少的场合
- 数据量太小不适合。数据量过小时,和线性查找耗时差不多。
- 数据量太大也不适合。二分查找依赖数组,因此需要连续内存,数据量太大,例如1GB的数据,将需要连续1GB的内存,这比较困难。
a. 最简单的情况:有序递增数组中,不存在重复元素
//二分查找有序非重复数组,返回下标,无则返回-1
int binary_search(int data[], int size, int search_data)
{
int low = 0, high = size - 1;
int mid = 0;
//采用while循环进行二分查找
while (low <= high)
{
mid = low + ((high - low) >> 1);
//若data[mid] == search_data,则直接返回下标
if (data[mid] == search_data)
{
return mid;
}
//若data[mid] < search_data,则查找数据处于mid右边
else if (data[mid] < search_data)
{
low = mid + 1;
}
//若data[mid] > search_data,则查找数据处于mid左边
else
{
high = mid - 1;
}
}
return -1;
}
b. 有序递增数组,查找第一个值等于给定值的元素。
可以在a代码中对查找相等进行区分,判断是否为首次出现。
//二分查找有序有重复数组,返回查找元素第一次出现的下标,无则返回-1
int binary_search_first_data(int data[], int size, int search_data)
{
int low = 0, high = size - 1;
int mid = 0;
//采用while循环进行二分查找
while (low <= high)
{
mid = low + ((high - low) >> 1);
//若data[mid] == search_data,则要判断mid是否为首个元素下标
if (data[mid] == search_data)
{
//若mid为0,或mid的前一个不为search_data,则为首个元素下标
if (mid == 0 || data[mid - 1] != search_data)
{
return mid;
}
else
{
high = mid - 1;
}
}
//若data[mid] < search_data,则查找数据处于mid右边
else if (data[mid] < search_data)
{
low = mid + 1;
}
//若data[mid] > search_data,则查找数据处于mid左边
else
{
high = mid - 1;
}
}
return -1;
}
c. 有序递增数组,查找最后一个值等于给定值的元素。
可以在c代码中对查找相等进行区分,判断是否为末次出现。
//二分查找有序有重复数组,返回查找元素最后一次出现的下标,无则返回-1
int binary_search_last_data(int data[], int size, int search_data)
{
int low = 0, high = size - 1;
int mid = 0;
//采用while循环进行二分查找
while (low <= high)
{
mid = low + ((high - low) >> 1);
//若data[mid] == search_data,则要判断mid是否为最后一个元素下标
if (data[mid] == search_data)
{
//若mid为0,或mid的后一个不为search_data,则为最后一个元素下标
if (mid == (size - 1) || data[mid + 1] != search_data)
{
return mid;
}
else
{
low = mid + 1;
}
}
//若data[mid] < search_data,则查找数据处于mid右边
else if (data[mid] < search_data)
{
low = mid + 1;
}
//若data[mid] > search_data,则查找数据处于mid左边
else
{
high = mid - 1;
}
}
return -1;
}
d. 有序递增数组,查找第一个大于等于给定值的元素。
//二分查找有序有重复数组,查找第一个大于等于给定值的元素,无则返回-1
int binary_search_first_exceed(int data[], int size, int search_data)
{
int low = 0, high = size - 1;
int mid = 0;
//采用while循环进行二分查找
while (low <= high)
{
mid = low + ((high - low) >> 1);
//若data[mid] < search_data,则查找数据处于mid右边
if (data[mid] < search_data)
{
low = mid + 1;
}
//若data[mid] >= search_data,则对mid的前一位进行判断
else
{
if (mid == 0 || data[mid - 1] < search_data)
{
return mid;
}
else
{
high = mid - 1;
}
}
}
return -1;
}
e. 有序递增数组,查找最后一个小于等于给定值的元素。
//二分查找有序有重复数组,查找最后一个小于等于给定值的元素,无则返回-1
int binary_search_last_below(int data[], int size, int search_data)
{
int low = 0, high = size - 1;
int mid = 0;
//采用while循环进行二分查找
while (low <= high)
{
mid = low + ((high - low) >> 1);
//若data[mid] > search_data,则查找数据处于mid左边
if (data[mid] > search_data)
{
high = mid - 1;
}
//若data[mid] >= search_data,则对mid的后一位进行判断
else
{
if (mid == size - 1 || data[mid + 1] > search_data)
{
return mid;
}
else
{
low = mid + 1;
}
}
}
return -1;
}