1. 二分查找法,顾名思义每次将待查找的列表范围折半,直到找到待查找元素,或者发现待查找元素不在当前的列表中。
2. 二分查找法的适用场景必须是应用在有序的列表中,才能表现出比顺序查找更好的性能。
3. 有序列表的元素值的递增方向可以是从小到大排列,也可以是从大到小排列。
4. 更优的算法是,待查找的范围是整个列表的子表(缩小查询范围),但索引必须连续,其实此种优化对二分查找法的效率提升并不明显,但是对于某种情况下顺序查询的性能提升还是巨大的。
5、 对于需要频繁进行增、删、改操作的列表(进而可以引申到对数据库中某个数据源的操作),实时排序会大大影响程序的整体性能,因此二分查找法适用于数据源相对静态(增删改操作对数据排序影响不大)、对并发查询性能要求高(注意每种算法都有其局限性)。
举例讲解:
上面依次排列有12个蓝色的桶,每个桶内放了一个数字卡片,且卡片数字递增。假设我们并不知道每个桶内卡片上的数字,需要每次取出卡片进行比较才能得到结果。那么如果想要知道卡片77在哪个桶内,需要怎么进行查找呢?
注释:列表的索引为每个桶的标号(下方红色字体),列表的索引值从0开始的,因此桶的标识也是从0开始。
继续回答上面的问题,我们可能首先想到的是顺序查找,这种算法逻辑处理简单,就是从第一个0号桶中开始,依次取出每个桶中的卡片与待查找的数据进行比较,直至找到数字是77的卡片 ,并得到桶号(列表索引值)是9。此种方法一共要经历10次循环的比较运算才能得到结果(这是在列表中存在带查找数据的情况下,否则情况会更糟)。 那么如果应用二分查找法会怎么样呢,这里先给出答案,二分查找法需要经历的循环比较次数为4次(log12)。
继续提问,上面的例子中,是以有12个元素的列表为例,那么如果列表包含1200个数据元素,顺其推理,顺序查找所需的时间应该是对于具有12个元素列表查找的100倍;并且很顺理成章的认为,二分查找法所需的时间也是对12个元素的列表查询的100倍。事实是这样么?答案是否定的。我们运用大O表示法O(n)和O(logn) 来分别表示这2种查询算法所需运算时间,O(n)所需的时间是线性增加的,但是O(logn)显然不是,它是对数时间,其时间增加值是离散量。在大O表示法中,n表示列表具有的元素数量,O(n)和O(logn)分别表示顺序查找法与二分查找法的最大运行次数(相对时间)。
如上图所示,联想到全国有14亿人(神联想),如果是待查询的元素是这个量级,那么二分查找法的最大循环运行次数为31次,假设每次循环执行时间为1ms计算,最多需要31ms可得到查询结果;如果是顺序查找呢,需要的时间超过16天(是不是心里落差有点大)。二分查找法的运行时间实际上是以2为底数n的对数,对数运算与幂运算互为逆运算,这里31的由来也就是log14亿(0.38)向上取整得出。
继续以上述的具有12个元素的列表进行详细的分析,我们定义变量left和right为待查询列表的左右边界索引,初始值left = 0,right = 0;定义 变量mid为每次待查询范围的中间元素索引值 ,mid = (left + right)// 2(向下取整)。
此节主要讲述了二分查找法的实现原理、优点及适用场景,并与顺序查找法进行了比较,突显出其对于有序列表进行查询的巨大性能优势。下节主要在视频中,讲述二分查找法的Python代码实现,以代码方式模拟对于不同数据量的列表(100、1000或1亿元素)查找时,以更加直观的方式突显出二分查找法的性能优势。