二分法查找使用的前提是一串数据必须是有序的(递增或递减),时间复杂度是O(lgN),查找速度特别快;
但是对于这样一串数据4 5 6 1 2 3,前一部分是递增,后一部分也是递增,这样一串数据怎么去使用二分法查找呢?
把一个数组最开始的若干个元素搬到数组的末尾,称之为数组的旋转。上面的 4 5 6 1 2 3就是数组 1 2 3 4 5 6的一个旋转。看看这样一道题:输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
测试用例:
功能测试(数组中有重复数字或者没有重复数字)
边界值测试(输入数组是一个升序排序的数组,只包含一个数字的数组)
特殊输入测试(输入NULL指针)
分析:
数组为空;
只有一个数字的数组;
正常数组(旋转前递增,无重复,数字个数大于一个);
有重复数字的数组;
一定要考虑数组中有相同数字的特例;4 5 6 1 2 3, 1 1 1 0 1 1。
开始解题:
我们先处理正常情况下的
处理有重复数字的:
0 1 1 1 1 1旋转之后的结果1 1 1 0 1 1
对于这样的我们无法知道mid是位于第一个区间还是第二个区间,只能去一个个遍历查找最小值;
int MinOrder(int arr[], int start, int end) //顺序查找最小值,处理有重复数字的情况
{
int result = arr[start];
while (start <= end)
{
if (arr[start] < result)
{
result = arr[start];
}
start++;
}
return result;
}
int MinBinary(int arr[], int length)
{
if (arr == NULL || length <= 0)
{
cout << "数组错误" << endl;
return -1;
}
int start = 0;
int end = length - 1;
int mid = 0;
if (length == 1) //只有一个元素
{
return arr[0];
}
while ((start + 1) != end)
{
mid = (start&end) + (start^end) >> 1;
if (arr[start] == arr[end] && arr[start] == arr[mid])
return MinOrder(arr, start, end);
if (arr[mid] >= arr[start])
{
start = mid;
}
else if (arr[mid] <= arr[end])
{
end = mid;
}
}
return arr[end];
}