Python提取TOP排名,用插入排序法和二分法排序比较

时间:2022-10-19 21:42:56

题目:如果有1000个分值,需要快速找到前10个是什么(并排序),怎么算更快


本人想到的是插入排序法:先将前10个排序作为初步结果(default_list),然后对剩余990个(rest_list)进行循环,每个值(rest_number)与default_list中的值比较,如果比里面的某个值大,那么删掉里面最小的。保持default_list只有10个值。等rest_list循环完毕,那么最终default_list结果TOP10。

里面有个细节

1  本人想到利用python自带的sorted函数,自认为是个比较慢的排序函数,但是对于10个值的排序,性能影响不大。于是我想到,开始就对default_list排序,这样最小值就是default_list[0],不需要再看其他的了。即rest_number>default_list[0],则说明结果会发生变化。去掉default_list[0],加上rest_number。但是,rest_number不一定是最小的,所以改变后需要再次排序,这就产生了我写的第一个函数insert_sort

2 如果不用sorted函数,严格按照插入排序,也就是需要找出到底rest_number排在哪个地方,于是要费点心思多写几行代码。默认sort是从小到大,假设是

[1,2,3,4,6,7,8,9,10,11],插入个5。个人喜欢用大于号,所以就从右往左对比,找到rest_number>default_list[i](i=3)。还得去掉最左边的值(最小,所以得去掉),所以新的列表是[1:i+1](也就是[2,3,4])+[rest_number](也就是[5])+[i+1:](也就是[6,7,8,9,10,11])得到最终default_list=[2,3,4,5,6,7,8,9,10,11]

看上去比较复杂,但实际运算却快了一些,这是第二个函数iso_insert_sort


与同学交流了下,他推荐我用二分法排序,先算出1000个值的均值,取大于它的值,得到约500个。再取均值,取大于的。当取到20以内时停止,将剩下十几个进行排序,并取前10个。看上去这个性能比较好,想想1000个值循环6次左右就到了20内了,第一次1000个值与均值对比,第二次500。总共只要对比不到2000次即可。而插入排序法要对比至少990次,最多990*10次。 第三个函数dichotomy_sort


到底哪个好呢?本人写了个程序将三个函数进行测试。为了增加复杂度,我将1000个取TOP10改成10000个取TOP100,再循环20次。

代码如下:

结果如下

i 0.00399994850159 iso 0.00399994850159 d 0.00300002098083
i 0.00600004196167 iso 0.00500011444092 d 0.00699996948242
i 0.00699996948242 iso 0.00600004196167 d 0.00800013542175
i 0.00800013542175 iso 0.00699996948242 d 0.0110001564026
i 0.0090000629425 iso 0.0090000629425 d 0.0140001773834
i 0.00999999046326 iso 0.0090000629425 d 0.0160000324249
i 0.010999917984 iso 0.00999999046326 d 0.0190000534058
i 0.0130000114441 iso 0.0119998455048 d 0.0249998569489
i 0.0130000114441 iso 0.0120000839233 d 0.0239999294281
i 0.0139999389648 iso 0.0130000114441 d 0.0260000228882
i 0.0149998664856 iso 0.0139999389648 d 0.0299999713898
i 0.0169999599457 iso 0.0160000324249 d 0.0329999923706
i 0.0169999599457 iso 0.0159997940063 d 0.0350000858307
i 0.018000125885 iso 0.0169999599457 d 0.0380001068115
i 0.0199999809265 iso 0.0179998874664 d 0.0409998893738
i 0.0240001678467 iso 0.0190000534058 d 0.0450000762939
i 0.0209999084473 iso 0.0199999809265 d 0.0460000038147
i 0.0250000953674 iso 0.0210001468658 d 0.0490000247955
i 0.0230000019073 iso 0.0209999084473 d 0.0529999732971
i 0.0230000019073 iso 0.0220000743866 d 0.0539999008179
Insert_sort method costs: 0.298000097275
Iso_Insert_sort method costs: 0.270999908447
Dichotomy_sort method costs: 0.577000379562

结论:

iso_insert_sort最快(但代码写起来费点心思),insert_sort其次。二分法最慢。

当TOPn与总数数量级越近,二分法越有快(也就是说二分法本身要比插入法快),反之取样越少,还是插入法更好。

讨论:

从结果看出,排序算法尽管循环重复的代码上完全一样,但运行时间普遍越来越长,二分法最严重,开始与插入法差不多,而后来明显比插入法慢很多,不知什么原因。

代码肯定是有待优化的,本人实力有限,可能因为编程能力导致算法因素小于编写因素导致结论不符实际,这种情况也难免。

————更新————

上述问题已经在http://bbs.csdn.net/topics/390745463?page=1#post-397064902 讨论过,确实为本人代码问题。

实际效果依然是二分法最好,而对于100/10000这种数量级差的话,heapq函数的性能最好。 详见该帖子