编程珠玑第9章二分搜索(有重复数字)中查找某数出现的第一个位置

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++;

}

你可能感兴趣的:(编程珠玑第9章二分搜索(有重复数字)中查找某数出现的第一个位置)