赞
踩
二分查找也称折半查找(Binary Search),是一种效率较高的查找方法。该算法要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。如果一个序列是无序的或者是链表,那么该序列就不能使用二分查找。
二分查找算法原理如下:
(1)若待查序列为空,则返回-1,并退出算法;
(2)若待查序列不为空,则将它的中间元素与目标数值进行比较,判断是否相等;
(3)若相等,则返回中间元素索引,并退出算法;此时已查找成功。
(4)若不相等,则比较中间元素与目标数值的大小;
(5)若中间元素 > 目标数值,则将当前序列的前半部分作为新的待查序列;
(6)若中间元素 < 目标数值,则将当前序列的后半部分作为新的待查序列;
(7)在新的序列上重新从第(1)步开始查找。
举例:在一个有序数组中查找某个数,并返回数组对应数值的下标。
- /* C语言实现 */
- int binary_search(int num[], int length, int target)
- {
- int left = 0, right = length -1; //注意right取值
-
- while(left <= right) { //注意此处约束条件
- int mid = (right + left) / 2;
- if (target == num[mid]) {
- return mid;
- } else if (target > num[mid]) {
- left = mid + 1;
- } else if (target < num[mid]) {
- right = mid - 1;
- }
- }
- return -1;
- }
二分查找的运行过程可以用二叉树来描述,这棵树通常称为“判定树”。
假设有有序序列a = {5,13,19,21,37,56,64,75,80,88,92},采用二分查找算法查找关键字为 21 的过程为:
图1 二分查找
图 1 中的有序表中做折半查找的过程,对应的判定树如下图:
图2 二分查找对应的判定树
注意,此图中叶子节点看似为父节点的右孩子节点,其实不然,这里的叶子节点既可以作为右孩子节点,也可以当作左孩子节点对待,都是可以的。
在判定树中可以看到,如果想在有序表中查找 21 的位置,只需要进行 3 次比较,依次和 56、19、21 进行比较,而比较的次数恰好是该关键字所在判定树中的层次(关键字 21 在判定树中的第 3 层)。
对于具有 n 个结点(查找表中含有 n 个关键字)的判定树,它的层次数至多为:log2n + 1
(如果结果不是整数,则做取整操作,例如: log211 +1 = 3 + 1 = 4
)。
同时,在查找表中各个关键字被查找概率相同的情况下,折半查找的平均查找长度为:ASL = log2(n+1) – 1
。
简单的二分查找算法无法处理左侧边界或右侧边界的问题。比如说有一个有序数组 nums = [1,2,2,2,3],target = 2,二分查找算法返回的索引是 2,这没错。但是如果我们想得到 target 的左侧边界,即索引 1,或者我想得到 target 的右侧边界,即索引 3,这样的话此算法是无法处理的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。