python数据结构与算法分析第二版_Python数据结构与算法分析 Day15

c91dc2ab8302ab6f66dc356c82a4e705.png

Python数据结构与算法分析 Day15

0 1

二分查找

对于有序表,有没有更好更快的查找算法呢?在顺序查找中,如果第一个数据项不是要查找的数据项,那最多还有n-1个数据项查找,那我们能不能利用有序表的特性减少对比数据项的范围呢。这里我们就来探索一下二分法,二分查找不是从第一个元素开始搜索列表,而是从中间的元素着手。

我们从列表中间开始比对!

a1d021b7c57e685ebf4866b3a61eb504.png

无论如何,我们都会将比对范围缩小的原来的一半:n/2,下图展示了用二分法查找元素54,整个列表二分查找到元素44,44<54对右半部分在进行二分查找,查找结果为65,65>54,对其再次进行二分查找找到54,查找结束。

9cdb9e1c7ffddf301ff7d2a71f35be69.png

有序列表的二分搜素:

e210f36c77ac843eeb761f32d60777a5.png

聪明的你们是否发现了这也是分而治之的策略,将问题分为若干个更小规模的部分,通过解决每一小规模部分问题并将结果汇总得到原问题的解。

显然,递归算法就是一种典型的分治策略算法,二分法也适合用递归算法来实现。

8452203e40741686bdcd2ba508e66082.png

由于二分查找比对都将下一步的比对范围缩小一半,每次比对结束后剩余数据项如下表所示:

9fe26e531b0d5955cf53315e8761765b.png

当比对次数足够多以后,比对范围就会剩余一个数据项。无论这个数据项是否匹配查找项,比对都会结束。

4d204d2b722123b072c4552789571eaf.png

所以二分查找的算法复杂度是O(log n)

我们根据比对次数得出二分查找的算法复杂度是O(log n),但是算法还有一个因素注意到binarySearch(alist[:midpoint],item),这个递归调用使用了列表切片,而切片操作的复杂度是O(k),这样会使整个算法的时间复杂度稍有增加。

当然,我们采用切片是为了程序可读性更好,实际上也可以不切片,只传入起始和结束的索引值就可以了,这样就不会有切片的时间开销了。

虽然二分查找在时间复杂度上优于顺序查找,但也要考虑对数据项进行排序的开销。如果一次排序后可进行动多次查找那排序的开销就会降低;但如果数据集经常变动,查找次数相对较少,那么可能直接用无序表和顺序查找来的快捷。所以在算法的选择上,不仅要考虑时间复杂度,还要考虑到实际应用的情况。

52d3accd3cb2d113869d519e5efb6b2f.gif0 2 排序

排序是指将集合中的元素按某种顺序排列的过程。比如,一个单词列表可以按字母表或长度排序;一个城市列表可以按人口、面积或邮编排序。我们已经探讨过一些利用有序列表提高效率的算法(二分查找算法)。

排序算法有很多,对它们的分析也已经很透彻了。这说明排序是计算机科学中的一个重要的研究领域。给大量元素排序可能消耗大量的计算资源。与搜索算法类似,排序算法的效率与待处理元素的数目相关。对于小型集合,采用复杂的排序算法可能得不偿失;对于大型集合,需要尽可能充分地利用各种改善措施。

在讨论具体的算法之前,先思考如何分析排序过程。首先,排序算法要能比较大小。为了给一个集合排序,需要某种系统化的比较方法,以检查元素的排列是否违反了顺序。在衡量排序过程时,最常用的指标就是总的比较次数。其次,当元素的排列顺序不正确时,需要交换它们的位置。交换是一个耗时的操作,总的交换次数对于衡量排序算法的总体效率是很重要的。

52d3accd3cb2d113869d519e5efb6b2f.gif0 3 冒泡排序

冒泡排序的算法思路在于对无序表进行多趟比较交换,每趟包括了多次两两相邻比较,并将逆序的数据项互换位置,最终将本趟的最大项放在位置上。经过n-1次比较交换实现整表排序,每趟的过程类似于气泡在水中不断上浮水面的过程。

第一趟比较交换有n-1对相邻数据进行比较,一旦经过最大项就将最大项一路交换到最后一项;第二趟比较交换时最大项已经就位,共有n-2对相邻数据进行比较,直到第n-1趟完成后,最小项在列表的首位就不需要处理了。下图展示了冒泡排序的第一轮遍历过程,深色的是正在比较的元素。

ff8040e00e45b38133cd32eed331e465.png

015b77fbc3d9329a772ba7cb6c03a0ae.png

52d3accd3cb2d113869d519e5efb6b2f.gif0 4

冒泡排序算法分析

在分析冒泡排序算法时要注意,无论一开始元素是如何排列的,给含有n个元素的列表排序总需要n-1趟,比对次数逐步从n-1减少到1,并包括可能发生的数据项交换。

d10f3616f1a623411b79a785399475d9.png

比对的时间复杂度是O(n^2)

关于交换次数时间复杂度也是O(n^2),通常每次饱含三次赋值:

最好的情况是列表在排序前已经有序,交换次数为0;最坏的情况是每次比对都要进行交换,交换次数等于比对次数;平均情况则是最差情况的一半。

冒泡排序通常作为时间效率较差的排序算法,来作为其他数据的对比基准。冒泡排序效率主要差在每个数据项在找到最终元素位置之前必须经过多次比对和交换,其中大部分操作是无序的。

冒泡排序也并不是没有优势的,不需要任何额外的存储空间开销。另外,通过监测每趟比对是否发生过交换可以提前确定排序是否完成,这也是其他多数排序算法无法做到的。如果某趟比对没有发生任何交换,说明列表已经排好了序,就可以提前结束算法。

对冒泡排序性能进行了修改,这种排序通常称为短冒泡

3984d70ac8e8ebcbd6d7af57c6dc9bc8.png

END
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值