概述
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
算法要求
- 必须采用顺序存储结构。
- 必须按关键字大小有序排列。下面的例子是从小到大排序。
算法图解
举例,我们要查找数字21:
首先根据算法要求找了一组数据,使用low、high、mid指针分别表示数据开始结束和中间位置。算法开始时指针分别在自己的位置。
递归开始,将21与mid指针的数字比较,结果大于21,因此high指针指向mid位置并且减一,然后重新计算mid指针的位置。
同样再次与mid指向的数字进行比较,21大于19,low指针指向mid的位置加一,重新计算mid,发现low指针和mid指针指向同一个位置,因此就找到数字21了。
算法分析
1、递归
1.创建并初始化数据
#define MAXSIZE 100
#define KeyType int
#define ERROR 0
typedef struct{
KeyType key;
}ElemType;
typedef struct{
ElemType *R;
int length;
}SSTable;
int CreateSTable(SSTable &ST){
ST.length=0;
ST.R=new ElemType[MAXSIZE];
if(!ST.R) exit(ERROR);
int n;
cout<<"请输入要输入数字的个数:"<<endl;
cin>>n;
for(int i=1;i<=n;i++){
cin>>ST.R[i].key;
ST.length++;
}
return 1;
}
ST.R 存放的是排好序的数据。如:11 12 13 14 15 16 17 18 19 20
ST.length 存放数据的长度。 如:10
2.递归查找要查找的数字
int Search_Bin(SSTable ST,KeyType key,int low ,int high){//递归算法
if(low>high) return -1;
int mid=low+(high-low)/2;
if(key<ST.R[mid].key){
return Search_Bin(ST,key,low,mid-1);
}
else if(key>ST.R[mid].key) return Search_Bin(ST,key,mid+1,high);
else{
cout<<"该数字在第:"<<mid<<"个位置";
}
}
mid保证了记录的位置始终是中间附近的位置
key记录了要查找的数字
low记录下标最小的位置,初始默认为1
high记录下标最大的位置
如果要查找的数字key小于中间位置mid的数字,那么递归进入mid左边部分;
如果要查找的数字key大于中间位置mid的数字,那么递归进入mid右边部分;
如果要查找的数字key不大于也不小于中间位置mid的数字,那么mid所在的数字就是要查找的数字;
递归停止条件是low大于high,说明查找完毕;查到或者没有查找。
在递归时,low和high在不停变化,如果进入左边递归时那么high等于mid-1(就是说此时最大的下标high等于中间位置mid减一的位置);如果进入右边递归时那么low等于mid+1(就是说此时最小的下标low等于中间位置mid加一的位置);
目的在于不断缩小数据的规模,直到找到或者找完所有数据为止。
2、非递归
1.同样的初始化数据
#define MAXSIZE 100
#define KeyType int
#define ERROR 0
typedef struct{
KeyType key;
}ElemType;
typedef struct{
ElemType *R;
int length;
}SSTable;
int CreateSTable(SSTable &ST){
ST.length=0;
ST.R=new ElemType[MAXSIZE];
if(!ST.R) exit(ERROR);
int n;
cout<<"enter the number :"<<endl;
cin>>n;
for(int i=1;i<=n;i++){
cin>>ST.R[i].key;
ST.length++;
}
return 1;
}
2.非递归查找要查找的数字
int Search_Bin(SSTable ST,KeyType key){//非递归算法
int low=1,high=ST.length,mid;
while(low<=high){
mid=(low+high)/2;
if(key==ST.R[mid].key) {
cout<<"add is "<<mid;
return 1;
}
else if(key<ST.R[mid].key) high = mid-1;
else low=mid+1;
}
return 0;
}
非递归使用while循环,停止条件同样是是low大于high。
在循环中首先计算中间元素的下标,然后将要比较的数字和中间位置的数字进行比较;如果等于,则找到;如果小于,那么进入中间位置的左边(即把最大的下标high变成中间下标减一的位置)再次进行循环;如果大于,那么进入中间位置的右边进行查找;
目的在于不断缩小数据的规模,直到找到或者找完所有数据为止。
二分查找案例
1、递归案例
#include<iostream>
#include<stdlib.h>
using namespace std;
#define MAXSIZE 100
#define KeyType int
#define ERROR 0
typedef struct{
KeyType key;
}ElemType;
typedef struct{
ElemType *R;
int length;
}SSTable;
int CreateSTable(SSTable &ST){
ST.length=0;
ST.R=new ElemType[MAXSIZE];
if(!ST.R) exit(ERROR);
int n;
cout<<"请输入要输入数字的个数:"<<endl;
cin>>n;
for(int i=1;i<=n;i++){
cin>>ST.R[i].key;
ST.length++;
}
return 1;
}
void print(SSTable ST){
for(int i=1 ; i<=ST.length ; i++)
cout<<ST.R[i].key<<" ";
}
int Search_Bin(SSTable ST,KeyType key,int low ,int high){//递归算法
if(low>high) return -1;
int mid=low+(high-low)/2;
if(key<ST.R[mid].key){
return Search_Bin(ST,key,low,mid-1);
}
else if(key>ST.R[mid].key) return Search_Bin(ST,key,mid+1,high);
else{
cout<<"该数字在第:"<<mid<<"个位置";
}
}
int main(){
SSTable ST;
CreateSTable(ST);
print(ST);
int n;
cout<<endl<<"输入要查找的数字 :";
cin>>n;
Search_Bin(ST,n,1,ST.length);
}
2、非递归案例
#include<iostream>
#include<stdlib.h>
using namespace std;
#define MAXSIZE 100
#define KeyType int
#define ERROR 0
typedef struct{
KeyType key;
}ElemType;
typedef struct{
ElemType *R;
int length;
}SSTable;
int CreateSTable(SSTable &ST){
ST.length=0;
ST.R=new ElemType[MAXSIZE];
if(!ST.R) exit(ERROR);
int n;
cout<<"enter the number :"<<endl;
cin>>n;
for(int i=1;i<=n;i++){
cin>>ST.R[i].key;
ST.length++;
}
return 1;
}
void print(SSTable ST){
for(int i=1 ; i<=ST.length ; i++)
cout<<ST.R[i].key<<" ";
}
int Search_Bin(SSTable ST,KeyType key){//非递归算法
int low=1,high=ST.length,mid;
while(low<=high){
mid=(low+high)/2;
if(key==ST.R[mid].key) {
cout<<"add is "<<mid;
return 1;
}
else if(key<ST.R[mid].key) high = mid-1;
else low=mid+1;
}
return 0;
}
int main(){
SSTable ST;
CreateSTable(ST);
print(ST);
int n;
cout<<endl<<"enter your number :";
cin>>n;
Search_Bin(ST,n);
}