折半查找,也称二分查找,是一种效率较高的查找方法。
要求线性表必须采用 顺序结构,表中元素按关键字 有序排列。
int Search_Bin (SSTable ST, KeyType key) {
int low = 1, high = ST.length;
while (low <= high) { // 注意不是low<high,因为low=high时,查找区间还有最后一个结点,还要进一步比较
int mid = (low + high) / 2;
if (ST[mid].key == key) return mid;
else if (ST[mid].key > key) high = mid - 1;
else (ST[mid].key < key) low = mid + 1;
}
return 0;
}
注:该算法可改为递归实现
算法分析:
折半查找过程可用二叉树来描述,结点值不是记录的关键字,二是记录在表中的位置序号。
把当前查找区间的中间位置作为根,左子表和右子表分别作为根的左子树和右子树,由此得到的二叉树称为折半查找的 判定树 。
借助判定树,易得折半查找的平均查找长度。
假设有序表的长度\(n=2^h - 1\),则判定表的深度\(h=log_2(n+1)\)的满二叉树。
树中层次为\(1\)的结点有\(1\)个,层次为\(2\)的结点有\(2\)个,...,层次为\(h\)的结点有\(2^{h-1}\)个。
平均查找长度
\[ASL=\sum_{i=1}^{n}{P_iC_i} = \frac{i}{n}\sum_{j=1}^{h}{j·2^{j-1}} = \frac{n+1}{n}log_2(n+1)-1\]
当n较大时,可有下列近似结果\(ASL=log_2(n+1)-1\)
优点:比较次数少,查找效率高
缺点:对表结构要求高,只能用于顺序存储的有序表。查找前需要排序,排序本身也会消耗时间。为保持有序性,插入和删除时,也需耗时运算。
因此, 折半查找不适用于数据元素经常变动的线性表。