Python实现二分法查找及优化的示例详解
作者:Python?集中营 发布时间:2023-10-12 14:20:44
二分查找法(Binary Search)是一种在有序数组中查找某一特定元素的算法,它的思想是将数组从中间分成两部分,判断目标元素在哪一部分中,然后继续在相应的部分中进行查找,直到找到目标元素或者确定目标元素不存在为止。
在本文中,我们将使用 Python 实现二分查找算法,并深入探讨算法的原理和实现细节。
1.二分查找的原理
二分查找法适用于有序数组中查找某一特定元素的场景,它的原理是将有序数组分成两个部分,每次取中间位置的元素与目标元素进行比较,根据比较结果确定要查找的元素在左边部分还是右边部分,然后继续在相应的部分中进行查找。
这样每次都能将待查找区间缩小一半,直到找到目标元素或者确定目标元素不存在为止。
二分查找法的时间复杂度为 O(log n),其中 n 表示数组的长度。这是因为每次查找都将查找区间缩小一半,最坏情况下需要查找 log n 次。
2.二分查找的实现
接下来,我们将使用 Python 实现二分查找算法。首先,我们定义一个函数binary_search,接收两个参数:一个有序数组 arr 和一个目标元素 target。
函数返回目标元素在数组中的下标,如果不存在则返回 -1。
def binary_search(arr, target):
left = 0
right = len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
在这个函数中,我们定义了两个指针 left 和 right,分别指向数组的第一个元素和最后一个元素。
然后,我们进入一个循环,直到 left > right 为止。在每次循环中,我们计算中间位置的下标 mid,并将 arr[mid] 与 target 进行比较。
如果 arr[mid] 等于 target,说明我们已经找到了目标元素,直接返回 mid。如果 arr[mid] 小于 target,说明目标元素在右边部分,我们将 left 指针移到 mid 的右边一位。
如果 arr[mid] 大于 target,说明目标元素在左边部分,我们将 right 指针移到 mid 的左边一位。这样不断缩小查找区间,直到找到目标元素或者确定目标元素不存在为止。下面是一个使用例子:
arr = [1, 3, 5, 7, 9]
target = 7
result = binary_search(arr, target)
if result == -1:
print("Element is not present in array")
else:
print("Element is present at index", result)
在这个例子中,我们定义了一个有序数组 arr 和一个目标元素 target,并调用了 binary_search 函数。
如果目标元素存在于数组中,函数将返回目标元素在数组中的下标;否则返回 -1。
在这个例子中,目标元素 7 存在于数组中,函数将输出 “Element is present at index 3”。
3.二分查找的优化
虽然二分查找法的时间复杂度为 O(log n),但是在实际应用中,我们可以通过一些优化来进一步提高算法的效率。
(1)查找区间的左右边界
在二分查找法中,我们需要定义一个查找区间,通常用 left 和 right 两个指针来表示。
在每次循环中,我们需要判断 left 和 right 是否重合,如果重合则说明查找区间为空,目标元素不存在于数组中。
这个判断过程需要进行多次,可以通过在循环条件中直接判断 left 和 right 是否相邻来减少判断次数,如下所示:
while left < right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
if arr[left] == target:
return left
else:
return -1
在这个优化中,我们将循环条件改为 left < right,这样每次循环结束后,left 和 right 最多相差 1。
在循环结束后,我们需要判断 left 和 right 是否指向目标元素。如果 arr[left] 等于 target,则说明目标元素存在于数组中,返回 left;否则返回 -1。
(2)位运算代替除法运算
在计算中间位置的下标 mid 时,我们通常使用除法运算符 //。然而,除法运算符比位运算符效率低得多,因此我们可以使用位运算符 >> 来代替除法运算符 //,如下所示:
mid = (left + right) >> 1
在这个优化中,我们将除以 2 改为右移 1 位,即将二进制数向右移动一位,相当于除以 2。这样可以减少计算中间位置的下标所需的时间。
(3)使用 bisect 库
Python 中的 bisect 库提供了一些实用的函数,可以帮助我们更方便地进行二分查找。
其中,bisect_left 函数和 bisect_right 函数分别用于在有序数组中查找某一元素的插入位置。
这两个函数的区别在于,当有多个相同的元素时,bisect_left 函数返回第一个位置,而 bisect_right 函数返回最后一个位置。
下面是一个使用 bisect 库进行二分查找的例子:
import bisect
arr = [1, 3, 5, 7, 9]
target = 7
index = bisect.bisect_left(arr, target)
if index < len(arr) and arr[index] == target:
print("Element is present at index", index)
else:
print("Element is not present in array")
在这个例子中,我们使用 bisect.bisect_left 函数在有序数组 arr 中查找目标元素 target 的插入位置。
如果插入位置小于数组长度,并且插入位置处的元素等于目标元素,则说明目标元素存在于数组中,输出其下标;否则输出 “Element is not present in array”。
4.总结
二分查找法是一种高效的查找算法,适用于有序数组中查找某一特定元素的场景。通过将数组从中间分成两部分,每次取中间位置的元素与目标元素进行比较,可以将待查找区间缩小一半,从而降低查找的时间复杂度。
在实现二分查找算法时,我们需要定义一个查找区间,通常用 left 和 right 两个指针来表示。在每次循环中,我们计算中间位置的下标 mid,并将 arr[mid] 与 target 进行比较。如果 arr[mid] 等于 target,说明我们已经找到了目标元素,直接返回 mid。
如果 arr[mid] 小于 target,说明目标元素在右边部分,我们将 left 指针移到 mid 的右边一位。如果 arr[mid] 大于 target,说明目标元素在左边部分,我们将 right 指针移到 mid 的左边一位。这样不断缩小查找区间,直到找到目标元素或者确定目标元素不存在为止。
在实际应用中,我们可以通过一些优化来进一步提高算法的效率。例如,可以在循环条件中直接判断 left 和 right 是否相邻来减少判断次数;可以使用位运算符 >> 来代替除法运算符 //,减少计算中间位置的下标所需的时间;可以使用 bisect 库提供的函数来进行二分查找,更方便地实现算法。
来源:https://mp.weixin.qq.com/s/KAvg2Lr_XnuNzMiGPqv9fQ


猜你喜欢
- 超酷的js图片轮换/轮播 渐变效果··来自腾讯刚刚在腾讯女性频道上看到一个很酷的图片渐变轮换效果·····于是乎····抠下来了···分享·
- swiper是我之前做前端页面会用到的一个插件,我自己认为是非常好用的。swiper提供了形式多种多样、适应各个终端的轮播图效果。本文是小编
- 由于在遭遇到这个页面之前我们一 * 互刚好在讨论交互设计原则之类的话题,其中有一条是:包容性,即满足主体用户需求的同时,尽可能兼顾非主体用户需
- 1、绝对导入和相对导入绝对导入:按照sys.path顺序搜索,先主目录(sys.path中第一项''),然后PYTHONPA
- 各人觉得这些LOGO的设计都很好,简洁,明了,大方。特整理出来与大家分享,希望能吸取设计经验。asp之家祝愿各位09年身体健康,万事如意,网
- 如下所示:<span style="font-family: Arial, Helvetica, sans-serif;&q
- Google Talk是一个功能很简洁的即时通讯工具,尤其是它的文字输入区域,不同于其他IM,除了一个文字输入区域外没有任何其他操作。但是用
- 在做项目时发现,很多场合都可能用到Input但又想让它具有select的特性,研究了一下,似乎可以实现,下面的代码可以大概说明我的意图,但实
- 本文简单总结了一下Python处理时间和日期方面的模块,主要就是datetime、time、calendar三个模块的使用,希望这篇文章对于
- 导入组件首先导入需要的组件,pygame游戏组件,time是时间组件import pygame, time, sysfrom pygame.
- linux下mysql默认是要区分表名大小写的。mysql是否区分大小写设置是由参数lower_case_table_names决定的,其中
- 说到转置操作,顺便提及矩阵与数组的区别:矩阵:数学里的概念,其元素只能是数值,这也是区别于数组的根本所在数组:计算机中的概念,代表一种数据组
- mysql 模糊查询 concat()concat() 函数,是用来连接字符串。精确查询: select * from user where
- python的列表很重要,学习到后面你会发现使用的地方真的太多了。最近在写一些小项目时经常用到列表,有时其中的方法还会忘哎!所以为了复习写下
- 句柄(handle)是C++程序设计中经常提及的一个术语。它并不是一种具体的、固定不变的数据类型或实体,而是代表了程序设计中的一个广义的概念
- 当我们建立一个数据库时,并且想将分散在各处的不同类型的数据库分类汇总在这个新建的数据库中时,尤其是在进行数据检验、净化和转换时,将会面临很大
- Nodejs 的大部分核心 API 都是基于异步事件驱动设计的,事件驱动核心是通过 node 中 Events 对象来实现事件的发送和监听回
- inet_pton是一个IP地址转换函数,可以在将IP地址在“点分十进制”和“二进制整数”之间转换,而且inet_pton和inet_nto
- 如下所示:url = u'http://tieba.baidu.com/f?kw=权利的游戏&ie=utf-8&pn
- 用div+css制作页面,想实现左右两部分固定宽度,而中间部分不固定,并随着屏幕分辨率的的变化而自动伸缩。大家可知道应该如何实现? &nbs