二分查找: 前提是有序的序列。
int BinarySearch(int A[], int left ,int right,int value)
或者int BinarySearch(int A[], int n,int value)
// n为数组长度。
value 为要查找的数。
(可以在一个序列中查找等于某个值a的元素的位置,也可以查找大于a的第一个元素的位置)
1.idea:
在一个有序的序列中(如升序),查找某个数a,可以将a与序列的中间位置元素比较,如果a<中间值,则在
左半部分找,否则到右半部分找,直至找到,或者所查找的序列范围为空。
2.input:
数组A(有序),left 通常为0,right通常为n-1,要查找的值value
3.output:
value的位置
4.伪代码:
(1)找出value的位置。
1.左闭右闭 即[ ]类型
循环体外的初始化条件,与循环体内的迭代步骤, 都必须一致;
如果循环体初始化时,是以左闭右开区间为边界的,那么循环体内部的迭代也应该如此.如果两者不一致,会造成程序的错误.
left=0;
right=n-1;//n为数组的长度。
while(left<=right){
mid=left+(right-left)/2;
//不用mid=(left+right)/2;是由于担心left+right越界。
case:
A[mid]<value : left=mid+1;
A[mid]>value : right=mid-1;
A[mid]=value : return mid;
return -1;// 没有找到则return -1
}
具体实现:
1.错误代码:
int BinarySearch(int A[], int left ,int right,int value)
{
int mid=-1;
while(left<=right){
mid=left+(right-left)/2;
//不用mid=(left+right)/2;是由于担心left+right越界。
if(A[mid]<value )
left=mid+1;
else if (A[mid]>value )
right=mid-1;
else break;
}
return mid;
}
//可能找不到时也会返回值。
正确代码:
int BinarySearch(int A[], int left ,int right,int value)
{
int mid=-1;
while(left<=right){
mid=left+(right-left)/2;
//不用mid=(left+right)/2;是由于担心left+right越界。
if(A[mid]<value )
left=mid+1;
else if (A[mid]>value )
right=mid-1;
else return mid;
}
return -1;
}
调用时:BinarySearch(A,0,n-1,value);
递归实现:
int BinSearch(int Array[],int low,int high,int key/*要找的值*/)
{
if (low<=high)
{
int mid = (low+high)/2;
if(key == Array[mid])
return mid;
else if(key<Array[mid])
return BinSearch(Array,low,mid-1,key);
else if(key>Array[mid])
return BinSearch(Array,mid+1,high,key);
}
else
return -1;
}
2.左闭右开类型 即[ )
伪代码:
left=0;
right=n;//n为数组的长度
while(left<right){
mid=left+(right-left)/2;
if(A[mid]>value)
right=mid;// 右开,所以right!=mid-1;
else if(A[mid]<value)
left=mid+1;//左闭
else return mid;
}
return -1;
具体实现:
int BinarySearch(int A[],int left ,int right,int value){
int mid;
while(left<right){
mid=left+(right-left)/2;
if(A[mid]>value)
right=mid;// 右开,所以right!=mid-1;
else if(A[mid]<value)
left=mid+1;//左闭
else return mid;
}
return -1;
}
----
(2)改进:
如果一个序列中与value值相同的元素有多个,如何返回第一个相同的元素的位置。
伪代码以及具体实现:
left=0;
right=n-1;
first=-1;//初始化first,如果没有找到则返回-1、
while(left<=right){
mid=left+(right-left)/2;
//不用mid=(left+right)/2;是由于担心left+right越界。
if(A[mid]<value )
left=mid+1;
else if (A[mid]>value )
right=mid-1;
else {
first=mid;
right=mid-1;
} // 用first保存mid值,并且查找范围不断从右向左推进。
}
return first;
2.查找到>=value的第一个元素的值。
left=0;
right=n-1;
first=-1;//初始化first,如果没有找到则返回-1、
while(left<=right){
mid=left+(right-left)/2;
//不用mid=(left+right)/2;是由于担心left+right越界。
if (A[mid]>=value )
{
first=mid;
right=mid-1;
}
//因为A[mid]>value,所以用first不断保存mid,且mid一直在从右往左移动
else {
left=mid+1;
} // 用first保存mid值,并且查找范围不断从右向左推进。
}
return first;
--------------------------------
总结:
(1)寻找第一个元素的位置,则缩小右边界的位置,right=mid-1;
如:查找第一个值为value的元素的位置:
if(array[mid]==value) {
first=mid;
right=mid-1;
}
如:查找>=value的第一个元素的位置:
if(array[mid]>=value){
first=mid;
right=mid-1;
}
(2)寻找最后一个元素的位置,则缩小左边界的位置,left=mid+1;
如:查找小于等于value的最后一个元素的位置:
if(array[mid]<=value){
low=mid+1;
}
===================
注意:
left ,right ,mid都使用有符号整数,不使用无符号整数;
比如:
在100,200,300中找20;
则:
left = 0, right = 2, mid =1 , a[mid] = 200 > 20;
left = 0, right = 0, mid = 0, a[mid] = 100 > 20;
left = 0, right = mid -1 = -1; 退出循环、如果使用无符号整数,则可能出错;