查找篇-二分查找

242 阅读2分钟

本文参考资料

  • 极客时间的《数据结构与算法之美》-王争
  • 《数据结构-严蔚敏版》

二分查找适用场景

二分查找适用于有序的顺序表,就是说查找序列必须是连续存储的。考虑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;
}