二分查找
在有序的序列中,每次都以序列的中间位置的数来与待查找的关键字进行比较,每次缩小一半的查找范围,直到匹配成功。
将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
非递归实现
public static Integer cycleSearch(int arr[], int target) {
//定义开始位置
int start = 0;
//定义结束位置
int end = arr.length - 1;
while (start <= end) {
//计算中位数
int mid = start + (end - start) / 2;
if (arr[mid] == target) {
return arr[mid];
} else if (arr[mid] < target) {
//如果中位数元素小于目标值,则将起始位置设置为mid++
start = mid++;
} else if (arr[mid] > target) {
//如果中位数元素大于目标值,则将结束位置设置为mid--
end = mid--;
}
}
return -1;
}
递归实现
public static Integer recursiveSearch(int start, int end, int[] arr, int target) {
int mid = start + (end - start) / 2;
if (arr[mid] == target) {
return arr[mid];
}else if (arr[mid] > target){
return recursiveSearch(start,mid--,arr,target);
}else if (arr[mid] < target){
return recursiveSearch(mid++,end,arr,target);
}
return -1;
}
复杂度
时间复杂度
最坏的情况下两种方式时间复杂度一样:O(log2 N)
空间复杂度
非递归方式:
由于辅助空间是常数级别的所以:
空间复杂度是O(1);
递归方式:
递归的次数和深度都是log2 N,每次所需要的辅助空间都是常数级别的:
空间复杂度:O(log2N )
中位数的计算
常用的写法。如果两个数太大,会有溢出的风险
public static int avg(int x ,int y){
return (x+y)/2;
}
正确的写法。把求平均数分成了2部分,a&b和a ^ b>>1,a&b相同的部分,a^b的差值,差值右移一位算出平均值,然后相加即可。
public static int avg(int a,int b){
return ((a&b) + ((a^b) >> 1));
}
在二分查找里,a一定是小于b的,所以可以这样
public static int avg(int a,int b){
// a <=b
return a+(b-a)/2;
}