0.有序数组的二分查找
/* 在升序数组arr[]中查找key,如果key存在,则返回其在数组中的位置index,否则返回 -1。*/
int BinarySearch(int arr[],int arr_size, int key)
{
if (arr == NULL)
{
return -1;
}
int low = 0;
int high = arr_size - 1;
int mid;
while (low <= high)
{
mid = (low + high) / 2;
if (arr[mid] == key)
{
return mid;
}
else if (arr[mid] > key)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
return -1;
}
测试用例:
//test1
int arr[] = { 1, 2, 3, 5, 6, 7 };
int key = 3;
//test2
int arr[] = { 1, 2, 3, 5, 6, 7 };
int key = 4;
//test3
int arr[] = { 1 };
int key = 3;
//test4
int *arr = NULL;
int key = 3;
1、二分查找变体:有序数组循环移动后,查找最小值
【题目】一个有序数组的元素经过循环移动,元素的顺序可能变为“3、4、5、6、7、1、2”。
找出数组中最小的那个元素,假设数组中元素各不相同。
这是一个有序数组,只是部分元素循环移动过,因此元素的排序肯定是从小到大,在某一个位置突然变小,接着又开始从小到大排列,那个从突然变小的“转折点”,就是最小元素。
比较最小元素与末尾元素(6>2), 说明 在 6 到 2 直接有从大变小再变大的转折点,需要继续在6和2的区间继续查找。
如果mid < j ,则说明mid 到 j 之间是正常排序的,不存在转折点,说明转折点要么在前半部分,要么不存在,因此,继续在[i,m]之间继续查找。
思路:
3、4、5、6、7、1、2
i m j : arr[m] > arr[j] : 最小元素在[m,j] 之间,i=m
i m j : arr[m] > arr[j] : 最小元素在[m,j] 之间,i=m
i m j : arr[m] < arr[j] : 最小元素在[i,m] 之间, j=m
im j : arr[m] > arr[j] : 最小元素在[m,j] 之间,i=m
什么时候停止呢?算是找到了最小值?
当j - i == 1 的时候(假设数组元素个数>=2),谁是最小元素呢?比较一下 arr[i] 和 arr[j] 即可知道!
然后再处理下特殊情况:数组元素个数=1,
非法情况:arr == NULL
/*
二分查找 变体:
【题目】一个有序数组的元素经过循环移动,元素的顺序可能变为“3、4、5、6、7、1、2”。
找出数组中最小的那个元素,假设数组中元素各不相同。
*/
// 返回有序数组循环移动后的最小值,index 带回其下标
int BinarySearch_Rotate_loop(int arr[], int arr_size, int *index)
{
if (arr == NULL)
{
*index = -1;
return 0;
}
if (arr_size == 1)
{
*index = 0;
return arr[0];
}
int low = 0;
int high = arr_size - 1;
int mid = -1;
while ( high - low != 1 )
{
mid = (low + high) / 2;
if (arr[mid] < arr[high])
{
high = mid;
}
else if (arr[mid] > arr[high])
{
low = mid ;
}
}
// 退出循环的时候 j - i == 1
if (arr[low] < arr[high])
{
*index = low;
return arr[low];
}
else
{
*index = high;
return arr[high];
}
}
/* 测试用例 */
int arr1[] = { 3, 5, 6, 7, 1, 2 };
int arr2[] = { 6, 7, 1, 2, 3, 5 };
int arr3[] = { 1, 2, 3, 5, 6, 7 };
int arr4[] = { 1 };
// int arr50[] = { }; // 无法实现空数组
int arr5[] = { NULL }; // 这个不是空数组,C中的NULL = 0 ; #define NULL 0
int * arr6 = NULL; // 空指针
2、思考
1)有序数组经过循环移动后,还能使用二分查找法,查找特定元素吗?
2)写代码循环移动一个数组。