二分查找
思路:
- 找到最后一个小于等于IP的元素
- 找到第一个大于等于IP的元素
前提条件:
- 数据有序
- 随机访问
实现:
- 递归实现
- 非递归(循环实现)
注意事项:
- 循环退出条件
- mid 的取值(重点防止越界)
- left 和 right的更新
#include<stdio.h>
#define SIZE(a) (sizeof(a) / sizeof(a[0]))
int bsearchByrecursion(int arr[], int n, int key);
int bsearchByloop(int arr[], int n, int key);
int searchFirstkey(int arr[], int n, int key);
int searchLastkey(int arr[], int n, int key);
int bsearchEqualorgreated(int arr[], int n, int key);
int bsearchEqualorless(int arr[], int n, int key);
int main(void)
{
int arr[] = { 0,2,2,2,2,2,20,30,31,32,34,40,100 };
int key = -50;
int index = bsearchEqualorless(arr, SIZE(arr), 22);
printf("index = %d\n", index);
return 0;
}
// 递归实现二分查找
int bsearch(int arr[], int left, int right, int key)
{
// 边界条件:区间为 0
if (left > right)
{
return -1;
}
// 递归公式
/*
存在溢出风险。
原因:eft可能不断增大,如果到极限状态,
也就是left达到了right-1的地步的时候刚好数组的长度又很大,
那么就可能导致left + right的溢出出现负数
int mid = (left + right) / 2;
*/
// int mid = left + (right - left) / 2; // 正确写法
int mid = left + (right - left >> 1);
if (key < arr[mid])
{
return bsearch(arr, left, mid - 1, key);
}
if (key > arr[mid])
{
return bsearch(arr, mid + 1, right, key);
}
return mid; // key == arr[mid];
}
int bsearchByrecursion(int arr[], int n, int key)
{
// 委托
return bsearch(arr, 0, n - 1, key);
}
// 循环实现二分查找
int bsearchByloop(int arr[], int n, int key)
{
int left = 0;
int right = n - 1;
// left = right说明还有一个元素,该元素还要和key进行比较
while (left <= right)
{
int mid = left + (right - left >> 1);
// 不能写成left = mid, right = mid;有可能出现死循环。
if (key > arr[mid])
{
left = mid + 1;
}
else if (key < arr[mid])
{
right = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
// 寻找第一个与 key 相等的元素
int searchFirstkey(int arr[], int n, int key)
{
int left = 0, right = n - 1, mid;
while (left <= right)
{
mid = left + (right - left >> 1);
if (key > arr[mid])
{
left = mid + 1;
}
else if (key < arr[mid])
{
right = mid - 1;
}
else
{
if (mid == 0 || arr[mid - 1] < key) // 短路原则,不可能越界
{
return mid;
}
// 如果不是第一个与 key 相等的
right = mid - 1;
}
}
return -1;
}
// 查找最后一个与 key 相等的元素
int searchLastkey(int arr[], int n, int key)
{
int left = 0, right = n - 1, mid;
while (left <= right)
{
mid = left + (right - left >> 1);
if (key > arr[mid])
{
left = mid + 1;
}
else if (key < arr[mid])
{
right = mid - 1;
}
else
{
if ((mid == n - 1) || (arr[mid + 1] > key))
{
return mid;
}
// 不是最后一个值等于 key 的元素
left = mid + 1;
}
}
return -1; // 数组中不存在该元素
}
// 查找第一个大于等于 key 的元素
int bsearchEqualorgreated(int arr[], int n, int key)
{
int left = 0, right = n - 1, mid;
while (left <= right)
{
mid = left + (right - left >> 1);
if (key > arr[mid])
{
left = mid + 1;
}
else
{
// 找到一个大于等于 key 的元素
if (mid == left || arr[mid - 1] < key)
{
return mid;
}
// 如果不是第一个大于等于 key 的,则继续在左边找
right = mid - 1;
}
}
return -1;
}
// 查找最后一个小于等于 key 的元素
int bsearchEqualorless(int arr[], int n, int key)
{
int left = 0, right = n - 1, mid;
while (left <= right)
{
mid = left + (right - left >> 1);
if (key < arr[mid])
{
right = mid - 1;
}
else
{
if (mid == right || arr[mid + 1] > key)
{
return mid;
}
left = mid + 1;
}
}
return-1
}
标签:二分,arr,right,int,mid,查找,key,left
From: https://www.cnblogs.com/MyXjil/p/17117760.html