binary search:search the first occurence of a number
查找的数中有重复的数
只需在原始的二分搜索基础上进行修改,当中间的数A[mid]与target值相同时,target值的第一次出现要么是在mid处,要么是在mid左边。若low与mid(low==mid)的闭区间只包含一个数,则返回值为mid,若low<mid,则修改high为mid
具体实现如下
#include<iostream> using namespace std; int binary_search(int A[],int target,int low,int high){ while(low<=high){ int mid=(low+high)/2; if(target<A[mid]) high=mid-1; else if(target>A[mid]) low=mid+1; else if(low<mid)//&&target==A[mid] high=mid; else //mid==low return mid; } return -1; } int main(){ int A[]={1,2,3,3,5,6,7,9}; cout<<binary_search(A,3,0,7)<<endl; int B[]={1,2,3,3,4,4,7}; cout<<binary_search(B,4,0,6)<<endl; return 0; }
编程珠玑上Column 9给出了另外一个解法。
首先虚拟出两个数组元素,x[-1],x[n],n为数组的size,实际上这两个元素不存在,循环时不变量是x[l]<t<x<=x[u]
这与一般二分搜索假设的范围有点不一样。因为l初始为-1,u初始为n,该条件初始时候成立,实际上这两个虚拟的元素在代码中未使用
invariant在循环中保持。
因为初始时u>=l+2
m>=l+1
l<=u-2
所以l+1<=m<=u-1
所以l<m<u
根据循环中的语句l<u在循环中是得到保持的
l=-1; u=n while(l+1!=u){ /*invariant :x[l]<t &&x[u]>=t &&l<u*/ int m=(l+u)/2; if(x(m)<t) l=m; else u=m; } p = u ; /*assert l+1==u&&x[l]<t&&x[u]>=t*/ if(p>=n || x[p]!=t) p=-1
关于编程珠玑中9.3中的代码
if p>1000|| x[p] !=t
p=-1
这里的条件p>1000应该改为p>=1000,因为p=1000的时候,数组已经越界了。
实际上该算法算出的p是可能等于1000。因为要使p=1000,那么目标值t肯定处于后半区别,即l=1000-512
l+i=1000,处在[1000-512,1000]的区间之内。而l的更新必定遵循l=1000-512+256+128+...+1的规律,该数必定是个奇数,l最大可能的值是1000-512+256+128+64+32+16+8+4+2+1=999而p=l+1=1000,这时求出的p是可能等于1000的,所以这里写成p>1000是不行的
9.3最后一个版本代码是循环展开之后的版本。
第7题求解某数的二进制序列中1的个数
int count =0;
while(x>0){
x=x&(x-1);
count++;
}