1.折半查找:在有序表(假设为递增)中
(1)取中间记录作为比较对象,若给定值与中间记录相等,则查找成功;
(2)若给定值小于中间记录,则在有序表的左半区继续查找;
(3)若给定值大于中间记录,则在有序表的右半区继续查找。
(4)不断重复上述过程,直到查找成功,或查找区域无记录,查找失败
2.折半查找的条件:
(1)数据必须有序
(2)顺序存储结构(数组)
3.非递归和递归两种方法:
#include <iostream>
using namespace std;
class LineSearch{
public:
LineSearch();
LineSearch(int a[],int n);
int BinSearch1(int k);
int BinSearch2(int low,int high,int k);
private:
int data[10];
int length;
};
LineSearch::LineSearch(){
length=0;
}
LineSearch::LineSearch(int a[],int n){
length=n;
for(int i=0;i<n;i++)
data[i]=a[i];
}
int LineSearch::BinSearch1(int k){
int mid,low=1,high=length;
while(low<=high){
mid=(low+high)/2;
if(data[mid]>k)
high=mid-1;
else if(data[mid]<k)
low=mid+1;
else
return mid;
}
return 0;
}
int LineSearch::BinSearch2(int low,int high,int k){
int mid;
if(low>high)//递归的边界条件
return 0;
else{
mid=(low+high)/2;
if(data[mid]>k)
BinSearch2(low,mid-1,k);
else if(data[mid]<k)
BinSearch2(mid+1,high,k);
else
return mid;
}
}
int main()
{
//通常把下标为0处空着
int a[10]={0,5,12,15,16,18,22,24,30,36};
LineSearch ls(a,10);
int x=ls.BinSearch1(10);
if(x)
cout<<"查找成功,查找的数字的下标是"<<x<<endl;
else
cout<<"查找失败"<<endl;
int y=ls.BinSearch2(1,9,12);//注意数组越界问题
if(y)
cout<<"查找成功,查找的数字的下标是"<<y<<endl;
else
cout<<"查找失败"<<endl;
return 0;
}
- 为避免溢出,mid也可以用mid=right+(left-right)/2表示
4.性能分析
(1)折半查找判定树:
- low>high时,判定树为空
- low<=high时,判定树的根节点是mid=(low+high)的数据。根结点的左子树是r[low]~r[mid-1]对应的判定树,根结点的右子树是r[mid+1]~r[high]对应的判定树。
最终由折半查找判定树可知,成功次数=表长,失败次数=表长+1
(2)平均查找长度只与表长有关,表长一定时,成功和失败的平均查找长度也是固定的。
例题一:
在包含n个元素,升序排列的数组a[n]中寻找比p小的、下标最大的元素
#include <iostream>
using namespace std;
//二分查找:在升序排列的数组a[n]中寻找比p小的、下标最大的元素
int BinSearch(int a[],int n,int p){
int left=0;
int right=n-1;
int flag=-1;
while(left<=right){
int mid=left+(right-left)/2;
if(a[mid]<=p){
left=mid+1;
flag=mid;
}
else
right=mid-1;
}
return flag;
}
int main()
{
int a[5]={2,4,6,8,10};
int x=BinSearch(a,5,7);
cout<<a[x]<<endl;
return 0;
}