二分查找法

概述

在介绍二分查找之前,对于基于数字索引的数组元素的查找,我们可能第一反应都是遍历这个数组,直到给定数组元素值和待查找的值相等时,返回索引值并退出,否则一直遍历到最后一个元素,如果还是没有找到则返回 -1,这样的查找虽然是简单粗暴了点,但是对于规模不大的数据集,也是没什么问题的,不过很明显,对于 n 个元素的数组,这种查找的时间复杂度是 O(n),随着数据规模的增加,性能会越来越差,设想如果数据集的长度是 40 亿(约 2 的 32 次方),那么最差的情况需要遍历数组 40 亿次,简直不敢想象需要花费多长时间!那有没有性能搞好的算法来解决这个问题呢?

在进一步探讨这个问题之前,我们先来看一个生活中的例子。我们日常生活中,很多人应该有这种经历,朋友、同学或者同事淘了个宝贝,神秘兮兮的过来让大家猜多少钱,在约定一个价格范围之后(比如 10-100),大家会七嘴八舌的猜起价格来:

同事A:新淘了个宝贝,猜猜多少钱?

同事B:50块。

同事A:高了。

同事C:30块。

同事D:40块。

同事A:高了。

同事E:36块。

同事A:对了。

如果我们用顺序遍历的逻辑,最差需要 91 次,才能猜到价格,现实生活中,没人会这么干,我们采用上面这种逻辑,只需要 4 次就猜到价格了,快了几十倍,而且数据量越大,优势越明显。基于这种思路,我们的算法科学家提炼出了二分查找算法,帮助我们在给定数据集中快速定位要查找的元素。

实现原理

所谓二分查找,针对的是一个有序的数据集合(这点很重要),查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。注意到二分查找针对的必须是已经排序过的有序数组,否则不能使用该算法。图示如下:

示例代码

<?php

    function binary_search($nums, $num)
    {
        return binary_search_internal($nums, $num, 0, count($nums) - 1);
    }

    function binary_search_internal($nums, $num, $low, $high)
    {
        if ($low > $high) {
            return -1;
        }

        $mid = floor(($low + $high) / 2);
        if ($num > $nums[$mid]) {
            return binary_search_internal($nums, $num, $mid + 1, $high);
        } elseif ($num < $nums[$mid]) {
            return binary_search_internal($nums, $num, $low, $mid - 1);
        } else {
            return $mid;
        }
    }

    $nums = [1, 2, 3, 4, 5, 6];
    $index = binary_search($nums, 5);
    print $index;

性能分析

很显然,二分查找的时间复杂度是 O(logn)。这是一个非常恐怖的数量级,有时候甚至比 O(1) 还要高效,比如我们要在开头提到的 40 亿个数字中查找某一个元素,也只需要32次(2 的 32 次方是 40 亿数量级),这真的是非常高效了,正因如此二分查找在线性表结构中的应用非常广泛。

但是使用二分查找需要注意一个前提,那就是针对有序数组,换言之,二分查找适用于变动不是很频繁的静态序列集,如果序列集变动很频繁,经常进行插入删除操作,那么就要不断维护这个序列集的排序,这个成本也很高,因此,这种情况下就不适用二分查找了,比如我们的数据库查询,增删改查很频繁,显然不是通过二分查找来进行查询的。

转载

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 2

应该排序前sort($nums)

4年前 评论

没看到最后,大概就猜到了转载 :joy:

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!