本文参考资料
- 极客时间的《数据结构与算法之美》-王争
- 《数据结构-严蔚敏版》
二分查找适用场景
二分查找适用于有序的顺序表,就是说查找序列必须是连续存储的。考虑2^32数据规模的查找序列,如果使用二分查找,最多32次查找就能够知道查找对象在不在查找序列中了。
简单二分查找代码实现
int binSearch(int *a, int l, int h, int k){
int mid;
while(l <= h){
mid = l + ((h - l) >> 1);
if(a[mid] == k){
return mid;
}else if(a[mid] > k){
l = mid + 1;
}else{
h = mid - 1;
}
return -1;
}
}
二分查找的变形
查找小于等于k的最后一个元素
int binS1(int* a, int l, int h, int k){
int mid;
while(l <= h){
mid = l + ((h - l) >> 1);
if(a[mid] > k){
h = mid - 1;
}else{
if(mid == n - 1 || a[mid + 1] > k){ //边界检测
return mid;
}
l = mid + 1;
}
}
return -1;
}
查找大于等于k的第一个元素
int binS2(int* a, int l, int h, int k){
int mid;
while(l <= h){
mid = l + ((h - l) >> 1);
if(a[mid] < k){
l = mid + 1;
}else{
if(mid == 0 || a[mid - 1] < k){
return mid;
}
h = mid - 1;
}
}
return -1;
}
查找最后一个等于k的元素
int binS3(int* a, int l, int h, int k){
int mid;
while(l <= h){
mid = l + ((h - l) >> 1);
if(a[mid] == k){
if(mid == n - 1 || a[mid + 1] > k){
return mid;
}
l = mid + 1;
}else if(a[mid] > k){
h = mid - 1;
}else{
l = mid + 1;
}
}
return -1;
}
查找第一个等于给定值的元素
int binS4(int* a, int l, int h, int k){
int mid;
while(l <= h){
mid = l + ((h - l) >> 1);
if(a[mid] == k){
if(mid == 0 || a[mid - 1] < k){
return mid;
}
h = mid - 1;
}else if(a[mid] > k){
h = mid - 1;
}else{
l = mid + 1;
}
}
return -1;
}
使用二分查找求一个数的平方根,要求精确到6位小数
计算机实质上是一个状态机。编程针对的是各种状态。容易分析得到,这里有这么几个主要状态,分别是mid、low、high以及是否精确到小数点第6位。
首先可以写出判断是否小数点是否精确到第6位的算法
int isUntilSix(int a, int b){
double ret = a - b;
if(ret < 0 && ret < -0.00001){
return -1;
}else if(ret > 0 && ret > 0.00001){
return 1;
}
return 0;
}
然后是二分查找的常规编程
double bin(int obj){
if(obj < 0) return -1;
double l = 0, h = obj;
double mid;
int ret;
while(l < h){
mid = l + (h - l) / 2;
ret = isUntilSix(mid * mid, obj);
if(ret == -1){ //小了一点
l = mid;
}else if(ret == 1){//大了一点
h = mid;
}else{// 满足要求
return mid;
}
}
return -1;
}