关于折半查找实现中的一个问题

本文探讨了折半查找算法的时间复杂度及其优化方法,包括解决数组索引溢出问题的策略,并提供了实例代码分析。
#include <stdio.h>
#include <math.h>
//线性查找:时间复杂度是O(n)
int linearSearch(int arr[],int target){
int i=0;
for(i=0;arr[i];i++){
if(arr[i]==target)
return i;
}
return -1;
}
//迭代折半查找:时间复杂度:T(n) = T(n/2) + c
//要访问一半的数字
int binarySearch(int arr[],int iLen, int target){
int first = 0;
int last = iLen - 1;
int mid;
while(first<=last){//=号必须
//mid = (first+last)/2;
mid = first-(last-first)/2;
if(arr[mid]==target) return mid;
else if(arr[mid]<target){
first = mid + 1;
}else if(arr[mid]>target){
last = mid - 1;
}
}
if(first>=last){
return -1;
}
}
//递归折半查找:时间复杂度:T(n)=O(Logn) Log以2为底
//
int binarySearchRecursive(int arr[],int start,int end, int target){
//int mid = (start+end)/2;
mid = start -(end-start)/2;
if(start<=end){//=号必须
if(arr[mid]==target) return mid;
if(arr[mid]>target) return binarySearchRecursive(arr,start,mid-1,target);
return binarySearchRecursive(arr,mid+1,end,target);
}
return -1;
}
void main(){
//int arr[] = [3,4,9,8,12];
int arr[] = {3,8,9,10,12};
int iLen = sizeof(arr)/sizeof(arr[0]);
printf("%ld\n", binarySearch(arr,iLen,8));
return;
}

​up为折半查找的代码。你会发现有这个代码:mid=(first+last)/2。
如果(first+last)的和大于int类型所能表示的最大值(231-1),这会有一个小问题:结果为一个负数。在C语言中会报索引超出边界的错误或进入无限循环?


​解决方案:
1、int mid = low + ((high - low)/2);
并不总是有效的。为什么呢? 
在C语言中,有符号的整数溢出是未定义的,这个说明有可能还是会溢出。

2、Java:
int mid = (low + high) >>> 1(总是高位补零)
3、C/C++:
int mid = ((unsigned int)low + (unsigned int)high)>>1(无符号的数右移,高位补零)
虽然在C语言中,无符号的整数溢出不是未定义的。但是这个计算出来还是有可能有问题:比如(UINT_MAX+1)/2结果是0
4、x+y=(x&y)*2+x^y; 用位运算肯定不会发生溢出了。

但是以上方法都脱离了一个事实,因为是对数组排序,数组是有大小限制的。
对于64位机来说最大的寻址空间是264
字节,整型如果是8字节,261字节是数组所能容纳的最大值,也就是说start和end只和最大为262,没有超出
​int能表示的最大值范围,也就肯定不会溢出了
​32位机也能用类似方法分析。


int arr[1<<30];//VC6.0编译报错:E:\MYWORKSPACE\cpluspluscode\binarySearch\binary.cpp(56) : error C2133: 'arr' : unknown size


参考:
http://locklessinc.com/articles/binary_search/

总结:

32位机还是64位机上,都​用兼容的site_t替代int。优化可以用也可以不用。
 



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值