提示:折半查找在考试和面试可能性高
加粗样式
一、折半查找原理
折半查找(二分查找):只适用于有序(升序或降序)的顺序表。不能用于链表。
理解二分查找:
下图中有一个升序表,假设我需要查找元素35,我如何实现折半查找;
设置low,mid,high三个指针分别指向:
low指向顺序表第一个元素; 作为每次二分查找左边界的标志;
high指向顺序表顺序表最后一个元素;作为每次二分查找右边界的标志;
mid指向low和high中间的元素;作为每次和待查找的元素比较的标志;
此时low=0; high=10; mid=(low+high)/2=5;
第一轮查找,直接比较mid指针(下标为5)所指的元素(25) 和 待查找的元素35,发现 25<35,
由此可知,待查找元素35应该在mid指针的右侧,即下图中红色区域内;
我们已知low为左边界的标志,我们此时要查找的元素可能在红色区域内,而此时我们的low指针在红色区域之外,所以此时我们需要缩小查找范围,使得low指针在红色区域之内,我们将low指向mid+1,因为mid已经比较过了,不符合,所以可以直接将low=mid+1,然后进行第二轮查找;图片如下所示:
此时low=mid+1=6; high=10;
mid=(low+high)/2=8;
第二轮查找,比较mid指针(下标为8)所指的元素(38) 和 待查找的元素35,发现 38>35,
由此可知,待查找元素35应该在mid指针的左侧,即下图中绿色区域内;
我们已知high为右边界的标志,我们此时要查找的元素可能在绿色区域内,而此时我们的high指针在绿区域之外,所以此时我们需要缩小查找范围,使得high指针在绿色区域之内,我们将high指向high-1,因为mid已经比较过了,不符合,所以可以直接将high=mid-1,然后进行第三轮查找;图片如下所示:
此时low=6; high=mid-1=7;
mid=(low+high)/2=6;
第三轮查找,比较mid指针(下标为6)所指的元素(30) 和 待查找的元素35,发现 30<35,
由此可知,待查找元素35应该在mid指针的右侧,即下图中紫色区域内;
我们已知low为左边界的标志,我们此时要查找的元素可能在红色区域内,而此时我们的low指针在红色区域之外,所以此时我们需要缩小查找范围,使得low指针在紫色区域之内,我们将low指向mid+1,因为mid已经比较过了,不符合,所以可以直接将low=mid+1,然后进行第二轮查找;图片如下所示:
此时low=mid+1=7; high=7;
mid=(low+high)/2=7;
第四轮查找,比较mid指针(下标为7)所指的元素(35) 和 待查找的元素35,发现 相等,
由此可知,待查找元素35的下标为7,此位置即为寻找位置;
那么我如果我查找的元素是34呢,前三轮比较和上面的步骤一致,在进行第四轮查找时,
比较mid指针(下标为7)所指的元素(35) 和 待查找的元素34,发现 35>34,
由此可知,待查找元素34应该在mid指针的左侧,那么high的值将变为high=mid-1=6;
此时low=7,high=6,左边界大于右边界时,说明查找失败,顺序表中不存在该元素;
代码实现
通过上面的解释,我们很容易就可以写出实现的代码,
第一种方法用循环实现每一轮比较,
循环结束的条件就是找到元素,返回元素位置;亦或者是low>high(左边界大于有边界),查找失败;
第二种方法是递归实现;代码如下。自行查看即可;
/*
* 程序名:binsearch.c,此程序演示折半查找。
* 作者:C语言技术网(www.freecplus.net) 日期:20210325
*/
#include <stdio.h>
#include <string.h>
// 迭代实现。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Bin_Search1(int *sstable,unsigned int len,int key)
{
int low,high,mid;
low=0; high=len-1; // 初始化low和high的值,设置初始区间。
while (low<=high)
{
mid=(low+high)/2; // 计算mid的值,取中间位置。
if (sstable[mid]==key) return mid; // 找到了待查找的元素。
else if (sstable[mid]>key) high=mid-1; // 继续在前半区间进行查找。
else low=mid+1; // 继续在后半区间进行查找。
}
return -1;
}
// 递归实现。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Bin_Search2(int *sstable,int key,int low,int high)
{
if (low>high) return -1;
int mid=(low+high)/2; // 计算mid的值,取中间位置。
if (sstable[mid]==key) return mid; // 找到了待查找的元素。
else if (sstable[mid]>key) Bin_Search2(sstable,key,low,mid-1); // 继续在前半区间进行查找。
else Bin_Search2(sstable,key,mid+1,high); // 继续在后半区间进行查找。
}
int main()
{
// 有序的顺序表。
int sstable1[]={1,2,3,4,5,6,7,8,9,12};
int len=sizeof(sstable1)/sizeof(int);
// 迭代
printf("result1=%d\n",Bin_Search1(sstable1,len,0));
printf("result1=%d\n",Bin_Search1(sstable1,len,1));
printf("result1=%d\n",Bin_Search1(sstable1,len,7));
printf("result1=%d\n",Bin_Search1(sstable1,len,10));
printf("result1=%d\n",Bin_Search1(sstable1,len,12));
printf("result1=%d\n",Bin_Search1(sstable1,len,15));
printf("\n");
// 递归
printf("result2=%d\n",Bin_Search2(sstable1, 0,0,len-1));
printf("result2=%d\n",Bin_Search2(sstable1, 1,0,len-1));
printf("result2=%d\n",Bin_Search2(sstable1, 7,0,len-1));
printf("result2=%d\n",Bin_Search2(sstable1,10,0,len-1));
printf("result2=%d\n",Bin_Search2(sstable1,12,0,len-1));
printf("result2=%d\n",Bin_Search2(sstable1,15,0,len-1));
return 0;
}
折半查找-效率分析
如何获取折半查找的判定树:
查找判定树的性质: