二分查找会更快吗?Python中的二分查找与线性查找性能测试

本文涉及的产品
性能测试 PTS,5000VUM额度
简介: 二分查找会更快吗?Python中的二分查找与线性查找性能测试

当您要检查某个元素是否在列表中时,有很多方法可以解决相同的问题。可以通过线性查找和二分查找来完成,但是要猜测哪个更快。

640.png

为什么?

如果你最近参加过面试,你就会知道二分查找是面试官的最爱。

您为什么要花时间学习二分查找?C ++编程朋友可能已经告诉过您。Python很慢。您想确保自己的程序不会比所需的速度慢。

学习Python时,您将学习进行线性查找以检查元素是否在列表中。当您学习编码时很好,但是如果列表中有60.000.000个元素会发生什么呢?

如果在包含11个元素的列表中进行线性查找,则必须遍历所有11个元素。如果您使用二分查找,最终可能要进行2次迭代,具体取决于您要查找的内容。请参见下面的图形。

显而易见,哪种方法更快。

开始学习Python时,您很可能已经使用了一百次列表。检查列表中是否有一个值是一项正常的任务,您之前已经看到过:

my_list= [1,2,3,3,5,11,12]
if11inmy_list:
returnTruereturnFalse

或者

my_list= [1,2,3,3,5,11,12]
foreachinlist:
ifeach==11:
returnTruereturnFalse

让我们开始看看如何实现二分查找。

怎么做?

让我们看看二分查找是如何工作的。

首先,我们需要确保列表是有序的。您可以使用.sort()或sorts()对列表进行排序,我使用.sort()在适当的地方修改列表。如果出于某种原因需要一个新列表,或者不想篡改原始列表,可以使用sorted()

这是我们的测试内容:

bin_list= [1,2,3,5,6,9,11,12,15,20,22]
search_value_a=15

我们要寻找15的值。

我们的起点。具有最小值和最大值的列表:

640.png

当我们做二分查找时,我们从寻找列表中的中间元素开始:

640.png

中间索引为5,值为9。首先我们要知道9是不是我们要找的数字。记住,我们要找的是15。如果不是,我们检查它是更高还是更低。在这个例子中,9比15小,所以我们需要设置一个新的最小值点。我们知道我们不再需要担心列表的下半部分。新的最小点将被设置为列表上部的第一个可能的项。

640.png

使用新的中点,我们检查这是否是我们要寻找的数字。在这种情况下,正好是15,这样这次查找就完成了。

如果我们要找的是2,而第一个中间值是9,你觉得这个算法会怎么做?你是对的。取而代之的是max指数。

640.png

640.png

640.png

640.png

代码

通俗的流程解释如下:

用列表和目标作为参数创建函数。确保列表是有序的。

获取列表长度- 1为最大,0为开始。循环将:

  1. 获得新的中间值
  2. 检查中间值是否高于或低于目标值。
  3. 检查结束后,将最小值或最大值移到中间。
  4. 如果middle == target,返回True
  5. 如果我们到达列表的末尾,则目标不在列表中

下面看看代码实现:

importrandomdefbinary_search(input_list , target_value):
'''Function executing binary search to find if element is in a list.parameters:- list- targetreturn value: True/False (bool)'''input_list.sort()
min_index=0max_index=len(input_list) -1whilemax_index>=min_index:
mid_index=(max_index+min_index)//2ifinput_list[mid_index] ==target_value:
returnTrueelifinput_list[mid_index] <target_value:
min_index=mid_index+1else:
max_index=mid_index-1returnFalsedefmain():
#bin_list=list(range(6,501))
bin_list= [1,2,3,5,6,9,11,12,15,20,22]
search_value_a=15search_value_b=7assertbinary_search(bin_list,search_value_a) ==Trueassertbinary_search(bin_list,search_value_b) ==Falseif__name__=='__main__':
main()


我们已经创建了一个具有两个参数的函数。列表和目标值。目标值就是我们要找的数字。这个列表就是我们要遍历的,用来寻找数字的列表。

def binary_search(input_list , target_value):

如果我们找到了目标值,我们将返回True。如果不是,我们将返回False。

我们要做的第一件事是对列表进行排序,并定义列表的最小索引和最大索引。

input_list.sort()
min_index=0max_index=len(input_list) -1

我们使用len(list)-1的原因是Python从0开始索引。测试列表的长度是11,但是最后一个索引是[10]。

现在,让我们进入主要的功能,循环:

whilemax_index>=min_index:
mid_index=(max_index+min_index)//2ifinput_list[mid_index] ==target_value:
returnTrueelifinput_list[mid_index] <target_value:
min_index=mid_index+1else:
max_index=mid_index-1

只要最大值不大于最小值,我们就继续。如果循环停止了,那就意味着我们已经折叠了列表,使得最大值小于最小值。此时,没有必要查找这个值,因为没有更多的列表了。

mid被设置为最大值和最小值的平均值。请注意我们是如何使用整数除法的,例如7//2将是3而不是3.5。这样,我们总是为索引得到一个干净的整数。

如果带有中间索引的列表项的值等于我们的目标值,我们就成功了!返回True,然后退出。

如果这个值小于目标值,我们知道我们必须把最小索引推到那个点。因此新的最小值是中间+1

如果该值不等于或小于目标值,则会较大。这意味着我们可以删除列表的顶部并将最大索引下压。max被设置为中间-1

如果您觉得难以理解,可以在代码中添加print(),以获得索引跳跃的可视化表示。

在while循环的mid_index =(max_index+min_index)//2之后添加这个:

print (f'min: {min_index} , mid: {mid_index} , max: {max_index}')

但是它更快吗?

该函数的时间复杂度为O(n),其中n为链表的长度。为了检验哪种查找更快,我们可以计算二分查找相对于线性查找的时间。

640.png

首先,我们需要写出一个线性查找函数:

deflinear_search(input_list, target_value):
foreachininput_list:
ifeach==target_value:
returnTruereturnFalse

下面我们可以进行对比了:

defbinary_performance():
run_setup='''from __main__ import binary_search'''run_code='''bin_list = list(range(6,501))binary_search(bin_list,15)'''performance=timeit.repeat(setup=run_setup,
stmt=run_code,
repeat=3,
number=10_000)
print(f'binary search performance = {round(min(performance),2)}')
deflinear_performance():
run_setup='''from __main__ import linear_search'''run_code='''lin_list = list(range(6,501))linear_search(lin_list,15)'''performance=timeit.repeat(setup=run_setup,
stmt=run_code,
repeat=3,
number=10_000)
print(f'linear search performance = {round(min(performance),2)}')
binary_performance()
linear_performance()

640.png

陷阱

如果您运行上面的代码(与原始代码合并),您将看到线性查找更快了。这是什么魔法?

有几个问题给二分查找带来了困难。

排序

列表的长度

低于目标的值

以上所有因素,让线性领先。现在让我们继续排序,先改变列表长度:

bin_list=list(range(1,10000))
lin_list=list(range(1,10000))

640.png

线性查找仍然占上风。让我们对函数进行排序,并在将列表传递给函数之前对其进行排序。(这对线性查找是不公平的,因为线性并不依赖于排序列表)。我们所要做的就是在列表排序时注释掉它。

640.png

二者速度比较接近了。

如果我们将目标值移动到7,500呢?现在我们的偏差很明显,因为我们真的想让二分更快。

640.png

这次的差异是极端的。下面的最后一个例子将使情况更加公平。

让我们以随机长度和随机目标创建一个随机列表。然后我们将为这两个函数运行100,000次。

test_list=list(range(1,random.randint(2,50000)))
test_number=random.randint(2,50000)
binary_search(test_list,test_number)

640.png

640.png

现在让我们运行10万次!,我相信这些结果。上图是排序后结果,下图需要进行排序

总结

二分比线性快吗?是的,但要看情况而定。

如果有人告诉你二分查找更快,那是因为它通常是更快的。

和往常一样,你必须看一看设置,不要每次都去找一个单一的解决方案,因为它“是最好的”。

我们从实验中看到,这取决于你在做什么。如果您有一个简短的列表,或者如果您在列表的下半部分寻找元素,那么执行线性查找可能会更好。

这也是编程之美。你不应该在不知道为什么的情况下使用一种方法来做某事。如果你还不知道二分查找,现在你有了另一个工具来做查找。只要你觉得它有用,就使用它。

我希望我们能在一件事上达成一致。二分查找是相当酷的!

相关实践学习
通过性能测试PTS对云服务器ECS进行规格选择与性能压测
本文为您介绍如何利用性能测试PTS对云服务器ECS进行规格选择与性能压测。
目录
相关文章
|
1月前
|
Web App开发 前端开发 JavaScript
探索Python科学计算的边界:利用Selenium进行Web应用性能测试与优化
【10月更文挑战第6天】随着互联网技术的发展,Web应用程序已经成为人们日常生活和工作中不可或缺的一部分。这些应用不仅需要提供丰富的功能,还必须具备良好的性能表现以保证用户体验。性能测试是确保Web应用能够快速响应用户请求并处理大量并发访问的关键步骤之一。本文将探讨如何使用Python结合Selenium来进行Web应用的性能测试,并通过实际代码示例展示如何识别瓶颈及优化应用。
94 5
|
1月前
|
测试技术 持续交付 Apache
Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
【10月更文挑战第1天】Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
111 3
|
4天前
|
Java 测试技术 持续交付
【入门思路】基于Python+Unittest+Appium+Excel+BeautifulReport的App/移动端UI自动化测试框架搭建思路
本文重点讲解如何搭建App自动化测试框架的思路,而非完整源码。主要内容包括实现目的、框架设计、环境依赖和框架的主要组成部分。适用于初学者,旨在帮助其快速掌握App自动化测试的基本技能。文中详细介绍了从需求分析到技术栈选择,再到具体模块的封装与实现,包括登录、截图、日志、测试报告和邮件服务等。同时提供了运行效果的展示,便于理解和实践。
23 4
【入门思路】基于Python+Unittest+Appium+Excel+BeautifulReport的App/移动端UI自动化测试框架搭建思路
|
2天前
|
Python
二分查找变种大赏!Python 中那些让你效率翻倍的搜索绝技!
二分查找是一种高效的搜索算法,适用于有序数组。其基本原理是通过不断比较中间元素来缩小搜索范围,从而快速找到目标值。常见的变种包括查找第一个等于目标值的元素、最后一个等于目标值的元素、第一个大于等于目标值的元素等。这些变种在实际应用中能够显著提高搜索效率,适用于各种复杂场景。
19 9
|
3天前
|
算法 数据处理 开发者
超越传统:Python二分查找的变种策略,让搜索效率再上新台阶!
本文介绍了二分查找及其几种Python实现的变种策略,包括经典二分查找、查找第一个等于给定值的元素、查找最后一个等于给定值的元素以及旋转有序数组的搜索。通过调整搜索条件和边界处理,这些变种策略能够适应更复杂的搜索场景,提升搜索效率和应用灵活性。
16 5
|
7天前
|
测试技术 持续交付 Apache
Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
24 3
|
6天前
|
缓存 测试技术 Apache
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
18 1
|
6天前
|
Web App开发 测试技术 数据安全/隐私保护
自动化测试的魔法:使用Python进行Web应用测试
【10月更文挑战第32天】本文将带你走进自动化测试的世界,通过Python和Selenium库的力量,展示如何轻松对Web应用进行自动化测试。我们将一起探索编写简单而强大的测试脚本的秘诀,并理解如何利用这些脚本来确保我们的软件质量。无论你是测试新手还是希望提升自动化测试技能的开发者,这篇文章都将为你打开一扇门,让你看到自动化测试不仅可行,而且充满乐趣。
|
1月前
|
缓存 测试技术 Apache
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
【10月更文挑战第1天】告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
59 4
|
1月前
|
测试技术 数据安全/隐私保护 开发者
自动化测试的奥秘:如何用Selenium和Python提升软件质量
【9月更文挑战第35天】在软件开发的海洋中,自动化测试是那艘能引领我们穿越波涛的帆船。本文将揭开自动化测试的神秘面纱,以Selenium和Python为工具,展示如何构建一个简单而强大的自动化测试框架。我们将从基础出发,逐步深入到高级应用,让读者能够理解并实现自动化测试脚本,从而提升软件的质量与可靠性。