算法总结-二分查找算法

二分查找也称折半查找(Binary Search),是一种效率较高的查找方法。该算法要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。如果一个序列是无序的或者是链表,那么该序列就不能使用二分查找。

1、二分查找算法原理

二分查找算法原理如下:

(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;
}

2、二分查找的性能分析

二分查找的运行过程可以用二叉树来描述,这棵树通常称为“判定树”。

假设有有序序列a = {5,13,19,21,37,56,64,75,80,88,92},采用二分查找算法查找关键字为 21 的过程为:

                                                             图1  二分查找 

 图 1 中的有序表中做折半查找的过程,对应的判定树如下图:

算法总结-二分查找算法_第1张图片

                                                            图2  二分查找对应的判定树 

注意,此图中叶子节点看似为父节点的右孩子节点,其实不然,这里的叶子节点既可以作为右孩子节点,也可以当作左孩子节点对待,都是可以的。

在判定树中可以看到,如果想在有序表中查找 21 的位置,只需要进行 3 次比较,依次和 56、19、21 进行比较,而比较的次数恰好是该关键字所在判定树中的层次(关键字 21 在判定树中的第 3 层)。
对于具有 n 个结点(查找表中含有 n 个关键字)的判定树,它的层次数至多为:log2n + 1(如果结果不是整数,则做取整操作,例如: log211 +1 = 3 + 1 = 4 )。
同时,在查找表中各个关键字被查找概率相同的情况下,折半查找的平均查找长度为:ASL = log2(n+1) – 1

3、二分查找算法的缺陷

简单的二分查找算法无法处理左侧边界或右侧边界的问题。比如说有一个有序数组 nums = [1,2,2,2,3],target = 2,二分查找算法返回的索引是 2,这没错。但是如果我们想得到 target 的左侧边界,即索引 1,或者我想得到 target 的右侧边界,即索引 3,这样的话此算法是无法处理的。

你可能感兴趣的:(数据结构与算法,算法,二分查找)