二分查找(lower_bound和upper_bound)

Posted cglongge

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分查找(lower_bound和upper_bound)相关的知识,希望对你有一定的参考价值。

 参考自博客:https://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html

一直以来对二分查找都是一知半解,终于今天安心的好好学习了一下

 ForwardIter lower_bound(ForwardIter first, ForwardIter last,const _Tp& val)算法返回一个非递减序列[first, last)中的第一个大于等于值val的位置。

    ForwardIter upper_bound(ForwardIter first, ForwardIter last, const _Tp& val)算法返回一个非递减序列[first, last)中第一个大于val的位置。

    lower_bound和upper_bound如下图所示:

 

技术分享图片

1, lower_bound

  这个序列中可能会有很多重复的元素,也可能所有的元素都相同,为了充分考虑这种边界条件,STL中的lower_bound算法总体上是才用了二分查找的方法,但是由于是查找序列中的第一个出现的值大于等于val的位置,所以算法要在二分查找的基础上做一些细微的改动。

   以下是我写的二分查找代码

#include<stdio.h>
int s[20];
int lowbound(int l,int r,int k){//求第一个大于等于k的位置 
	int mid;
	int pos;//记录位置 
	while(l<r){
		mid=(l+r)/2;
		if(s[mid]>=k){//因为要求第一个大于等于k的位置,所以当s[mid]==k时,我们要向左找第一个k 
			r=mid;//不能是mid-1,因为可能会到小于k的地方去 
			pos=r;
		}
		else//s[mid]<k时,往右边找第一个等于k的值 
		{
			l=mid+1;
			pos=l;
		}
	}
	return pos;
}
int upbound(int l,int r,int k){//求第一个大于k的位置 
	int mid;
	int pos;//记录位置 
	while(l<r){
		mid=(l+r)/2;
		if(s[mid]<=k){//因为要求第一个大于k的位置,所以当s[mid]<=k时,直接到右边找 
			l=mid+1;
			pos=l;
		}
		else//s[mid]<k时,找第一个大于k的位置,所以r不能等于mid-1,因为mid-1位置上的值可能小于等于k 
		{
			r=mid;
			pos=r;
		}
	}
	return pos;
}
int main(){
	int n;
	int i,j;
	int l,r,k; 
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d",&s[i]);
	}
	char c;
	getchar();
	while(scanf("%c",&c)!=EOF&&c!=‘E‘){
		
		if(c==‘U‘){
			scanf("%d%d%d",&l,&r,&k);
			printf("%d
",upbound(l,r,k));
		}
		else if(c==‘L‘){
			scanf("%d%d%d",&l,&r,&k);
			printf("%d
",lowbound(l,r,k));
		}
		getchar();
	}
	return 0;
}

  

STL中的实现比较精巧,下面贴出源代码:

下面的代码是STL中的lower_bound实现:

//这个算法中,first是最终要返回的位置
int lower_bound(int *array, int size, int key)
{
    int first = 0, middle;
    int half, len;//len为当前计算数组的长度
    len = size;

    while(len > 0) {
        half = len >> 1;
        middle = first + half;
        if(array[middle] < key) {     
            first = middle + 1;          
            len = len-half-1;       //在右边子序列中查找
        }
        else
            len = half;            //在左边子序列(包含middle)中查找
    }
    return first;
}

下面的代码是STL中的upper_bound实现:

int upper_bound(int *array, int size, int key)
{
    int first = 0, len = size-1;
    int half, middle;

    while(len > 0){
        half = len >> 1;
        middle = first + half;
        if(array[middle] > key)     //中位数大于key,在包含last的左半边序列中查找。
            len = half;
        else{
            first = middle + 1;    //中位数小于等于key,在右半边序列中查找。
            len = len - half - 1;
        }
    }
    return first;
}

  

以上是关于二分查找(lower_bound和upper_bound)的主要内容,如果未能解决你的问题,请参考以下文章

减而治之 - 二分查找 - lower_bound实现原理

二分查找

关于lower_bound()和upper_bound()

代码题—lower_bound和upper_bound算法

关于lower_bound( )和upper_bound( )的常见用法

关于set的lower_bound 和 std的lower_bound