在传统的算法设计技术的分类中,折半查找属于分治技术的典型应用。但是,由于折半查找与待查值每比较一次,根据比较结果使得查找的区间减半,所以,折半查找应该属于减治技术的成功应用。
【问题】应用折半查找方法在一个有序序列中查找值为 k 的记录。若查找成功,返回记录 k 在序列中的位置,若查找失败,返回失败信息。
【想法】折半查找 (binary search) 利用了记录序列有序的特点,其查找过程是:取有序序列的中间记录作为比较对象,若给定值与中间记录相等,则查找成功;若给定值小于中间记录,则在中间记录的左半区继续查找;若给定值大于中间记录,则在中间记录的右半区继续查找。不断重复上述过程,直到查找成功,或所查找的区域无记录,查找失败。其减治思想如下图所示。
例如,在有序序列 {7,14,18,21,23,29,31,35,38} 中查找 18 的过程如下图所示。
【算法】折半查找算法用伪代码描述如下。
算法:折半查找 BinSearch
输人:有序序列 {,,...,},待查值 k
输出:若查找成功,返回记录 k 的位置,若查找失败,返回失败标志 0
1.设置初始查找区间:low=1;high=n;
2.测试查找区间 [ low,high ] 是否存在,若不存在,则查找失败;否则
3.取中间点 mid = ( low+high ) / 2;比较 k 与 ,有以下三种情况:
3.1 若 k<,则 high=mid-1;查找在左半区进行,转步骤2;
3.2 若 k>,则 low= mid+1;查找在右半区进行,转步骤2;
3.3 若 k=,则查找成功,返回记录在表中位置 mid。
【算法分析】折半查找的过程可用判定树来描述,判定树中的每个结点对应有序序列中的一个记录,结点的值为该记录在有序序列中的位置。下图给出了具有11个结点的判定树。
可以看到,查找某个记录的过程,即是判定树中从根结点到该记录结点的路径,和待查值的比较次数等于该记录结点在树中的层数。为便于讨论,以深度为 k 的满二叉树 (n=-1) 为例,假设每个记录的查找概率相等,即 =1/n(1≤ i ≤n),而树的第 i 层上有 个结点,因此,折半查找的平均查找长度为:
所以,折半查找的时间复杂性为O()。
【算法实现】折半查找算法用JAVA语言描述如下:
public class HalfFind {
public static void main(String[] args)
{
int r[]={7, 14, 18, 21, 23, 29, 31, 35, 38};
int i=BinSearch1(r,9,18);
System.out.println("在数组中的下标是:"+i);
}
static int BinSearch1(int r[], int n, int k)
{
int low = 0, high = n - 1; //设置查找区间,注意数组下标从0开始
int mid;
while (low <= high) //当区间存在时
{
mid = (low + high) / 2;
if (k < r[mid]) high = mid - 1;
else if (k > r[mid]) low = mid + 1;
else return mid; //查找成功,返回元素序号
}
return 0; //查找失败,返回0
}
}
运行结果如下:
from:算法设计与分析(第2版)——王红梅 胡明 编著——清华大学出版社