基础知识
顺序查找(Sequential Search):从表中最后一个记录(或是第一个记录)开始,逐个进行记录的关键字和给定值的比较。若某个记录的关键字和给定值比较相等,则查找成功,找到所查记录;反之,若直至第一个记录(或最后一个记录),其关键字与给定值比较都不等,则表明表中没有所查记录,则查找不成功。
折半查找(Binary Search):折半查找是对有序表的查找中一种最常用的方法。它的查找过程先确定待查记录所在的范围(区间),然后逐步缩小范围直到找到或找不到该记录为止。
已知有如下11个数据元素的有序表(关键字即为数据元素的值):
(5,13,19,21,37,56,64,75,80,88,92)
使用折半查找来查找key=21的过程如图(1)所示,假设指针low和指针high分别指示待查元素所在范围的下界与上界,指针mid指示区间的中间位置,即mid =(low + high)/2。此例中假设用数组存储上述数据元素,则low和high的初始值分别为0和10,即[0,10]为待查区间,mid初始值为(0+10)/2=5,如图(1)①所示。此时指针mid所指数据元素为56,大于21,则说明待查元素若存在,必在区间[low,mid-1]范围内,即[0,4]内,则令high指向mid-1,即下标为4的元素mid=(0+4)/2=2,如图(1)②所示。此时指针mid所指数据元素为19,小于21,则说明待查元素若存在,必在区间[mid+1,high]范围内,即[3,4]内,则令low指向mid+1,即下标为3的元素,此时mid=(3+4)/2=3,如图(1)③所示。此时指针mid所指元素为21,与待查找的元素21相等,查找成功。
再看使用折半查找来查找key=85的过程如(2)所示,low、high、mid的初始值同上,如图(2)①。此时指针mid所指数据元素为56,小于85,则说明待查元素若存在,必在区间[mid+1,high]范围内,即[6,10]内,则令low指向mid+1,即下标为6的元素,此时mid=(6+10)/2=8,如图(2)②所示。此时指针mid所指数据元素为80,小于85,则说明待查元素若存在,必在区间[mid+1,high]范围内,即[9,10]内,则令low指向mid+1,即下标为9的元素,此时mid=(9+10)/2=9,如图(2)③所示。此时指针mid所指数据元素为88,大于85,则说明待查元素若存在,必在区间[low,mid-1]范围内,即[9,8]内,此区间不存在,说明查找失败,如图(2)④所示。
由上可知,折半查找过程是以处于区间中间位置记录的关键字和给定值进行比较,若相等,则查找成功;若不相等,则缩小范围,直至新的区间中间位置记录的关键字等于给定值或者查找区间的大小小于0(表明查找不成功)为止。
代码实现
顺序查找的实现非常简单,其实现如下:
折半查找算法有递归实现及非递归实现两种方法,其实现分别如下:
代码清单
在算法的测试中,我使用了随机数函数来产生测试数据并保存在文件中,再从文件中读取数据进行测试,过程较为麻烦。自己实现时可自行设计测试方法。
#include<stdio.h> #include<stdlib.h> #include<time.h> #define MAX_SIZE 10 /***************顺序查找********************/ int Search_Seg(int* array,int key) { //从最后一个元素往前进行顺序查找. //若找到,则返回元素下标;若未找到,则返回-1。 int i; for(i=MAX_SIZE-1;i>=0;i--) if(array[i]==key) return i; return i; } /***************折半查找的递归实现************/ int Search_Bin_Recursion(int* array,int key,int start,int end) { //在数组array下标为[start,end]区间中查找关键字为key的元素. //若找到,则返回元素下标;若未找到,则返回-1。 if(start<=end) { int mid=(start+end)/2; if(array[mid]==key)//找到待查元素 return mid; else if(array[mid]>key) return Search_Bin_Recursion(array,key,start,mid-1);//递归调用折半查找函数,继续在前半区间进行查找 else return Search_Bin_Recursion(array,key,mid+1,end);//递归调用折半查找函数,继续在后半区间进行查找 } return -1; } /**************折半查找的非递归实现***********/ int Search_Bin_nonRecursion(int* array,int key) { //在数组array中查找关键字为key的元素. //若找到,则返回元素下标;若未找到,则返回-1。 int low=0,high=MAX_SIZE-1; while(low<=high) { int mid=(low+high)/2; if(array[mid]==key)//找到待查元素 return mid; else if(array[mid]>key)//继续在前半区间进行查找 high=mid-1; else low=mid+1;//继续在后半区间进行查找 } return -1; } /*************选择排序**************/ void sort(int* array) { int i,j,minNo; for(i=0;i<MAX_SIZE-1;i++) { minNo=i; for(j=i+1;j<MAX_SIZE;j++) if(array[minNo]>array[j]) minNo=j; if(minNo!=i) { int t=array[i]; array[i]=array[minNo]; array[minNo]=t; } } } int main() { srand((unsigned)time(NULL));//以时间作为随机数种子 int i=0,key,n; int array[MAX_SIZE]; /**************随机产生测试数据,将产生的随机数写入文件*************/ FILE *in=fopen("datafile.txt","w"); if(in==NULL) { printf("Open file erroe!\n"); exit(0); } while(!feof(in)&&i!=MAX_SIZE) { fprintf(in,"%d ",rand()%100);//以时间为种子产生100以内的随机数 i++; } fclose(in);//注意别忘记 /**************从文件中读取测试数据到数组中********************/ i=0;//将i重置为0 FILE *out=fopen("datafile.txt","r"); if(out==NULL) { printf("Open file error!\n"); exit(0); } while(!feof(out)&&(i!=MAX_SIZE)) { fscanf(out,"%d",&array[i]); i++; } fclose(out); printf("文件中的随机数为:"); for(i=0;i<MAX_SIZE;i++) printf("%d ",array[i]); printf("\n"); printf("---------------测试顺序查找-------------------\n"); printf("请输入需要查找的元素:"); scanf("%d",&key); n=Search_Seg(array,key); if(n==-1) printf("查找失败。\n\n"); else printf("查找成功,查找元素的下标为%d。\n\n",n); sort(array);//折半查找前先对数组进行排序 printf("排序后的随机数为:"); for(i=0;i<MAX_SIZE;i++) printf("%d ",array[i]); printf("\n"); printf("---------------测试递归折半查找---------------\n"); printf("请输入需要查找的元素:"); scanf("%d",&key); n=Search_Bin_Recursion(array,key,0,MAX_SIZE-1); if(n==-1) printf("查找失败。\n\n"); else printf("查找成功,查找元素的下标为%d。\n\n",n); printf("---------------测试非递归折半查找-----------------\n"); printf("请输入需要查找的元素:"); scanf("%d",&key); n=Search_Bin_nonRecursion(array,key); if(n==-1) printf("查找失败。\n"); else printf("查找成功,查找元素的下标为%d。\n",n); return 0; }
运行结果: