`
JhonStryker
  • 浏览: 19140 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

网上的一篇关于sort()方法的分析

阅读更多

原文地址:http://blog.donews.com/maverick/archive/2006/07/09/951101.aspx

 

Python语言内置了sort方法,可以很方便地对某个List进行排序:
L = [6, 5, 1, 3, 4, 2]
L.sort()
print L

———- Run Python Program ———-
[1, 2, 3, 4, 5, 6]

某些时候,我们希望按照自己定义的排序规则来排序(例如,按关键词的权重排序,按人的年龄排序,等等)。在Java语言中,我们可以自定义Comparator来实现,Python中也提供了类似的办法。

若List中每个元素都是2-tuple,tuple中第一个元素为String类型的keyword,第二个元素为该字符串对应的权重(int类型),希望按照权重排序(从高到低),则可以这样:
def my_cmp(E1, E2):
    return -cmp(E1[1], E2[1])    #compare weight of each 2-tuple
                    #return the negative result of built-in cmp function
                    #thus we get the descend order

L = [('a', 0), ('b', 1), ('c', 2), ('d', 3)]
L.sort(my_cmp)
print L

———- Run Python Program ———-
[('d', 3), ('c', 2), ('b', 1), ('a', 0)]

正因为可以自定义cmp方法,我们不妨探究一下,built-in的sort方法,到底是采用的哪一种排序算法:
from random import shuffle

def my_cmp(E1, E2):
    print ‘E1:’, E1, ‘E2:’, E2
    return cmp(E1, E2)

L = range(0, 10)
shuffle(L)
print L
L.sort(my_cmp)

———- Run Python Program ———-
[5, 3, 7, 6, 2, 8, 9, 4, 1, 0]
E1: 3 E2: 5
E1: 7 E2: 3
E1: 7 E2: 5
E1: 6 E2: 5
E1: 6 E2: 7
E1: 2 E2: 6
E1: 2 E2: 5
E1: 2 E2: 3
E1: 8 E2: 5
E1: 8 E2: 7
E1: 9 E2: 6
E1: 9 E2: 8
E1: 4 E2: 6
E1: 4 E2: 3
E1: 4 E2: 5
E1: 1 E2: 6
E1: 1 E2: 4
E1: 1 E2: 3
E1: 1 E2: 2
E1: 0 E2: 5
E1: 0 E2: 3
E1: 0 E2: 2
E1: 0 E2: 1

可以看到,每次调用my_cmp,E1依次是List中的第2、3、4……直到最后一个元素,可以肯定sort不是采用的分治法(devide-and-conqure)
看前三次调用,可以发现sort采用的是典型的插入排序——也就是说,将新元素插入已排序部分的合适位置,查找位置时采用的似乎是从后向前线形探察的办法。从元素6开始,新元素不再直接与已排序部分的最后元素比较,而是先与中间值比较,采用二分检索探察合适位置,这样,可以把时间代价从n缩小到log(n)。
至此,我们可以认为,built-in的sort方法,采用的是“二分法插入排序”(binary insertion)的算法。

为了检测这个结论,可以输入一个已排序的数组,看看结果。
L = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
L.sort(my_cmp)

———- Run Python Program ———-
E1: 1 E2: 0
E1: 2 E2: 1
E1: 3 E2: 2
E1: 4 E2: 3
E1: 5 E2: 4
E1: 6 E2: 5
E1: 7 E2: 6
E1: 8 E2: 7
E1: 9 E2: 8
E1: 10 E2: 9

结果发现,比较的次数非常少,插入每个元素的时候,只会与它之前紧邻的元素比较,而不是二分检索。这真是个有意思的现象。

改一改程序
L = [0, 1, 2, 3, 4, 5, 6, 8, 7, 9, 10]
L.sort(my_cmp)

———- Run Python Program ———-
E1: 1 E2: 0
E1: 2 E2: 1
E1: 3 E2: 2
E1: 4 E2: 3
E1: 5 E2: 4
E1: 6 E2: 5
E1: 8 E2: 6
E1: 7 E2: 8
E1: 7 E2: 4
E1: 7 E2: 6
E1: 7 E2: 8
E1: 9 E2: 4
E1: 9 E2: 7
E1: 9 E2: 8
E1: 10 E2: 5
E1: 10 E2: 8
E1: 10 E2: 9

可以看到,在数字8以前,List中的元素都是有序的,于是sort算法也只比较欲插入元素和已排序序列的最后一个元素;一旦发现输入序列不是自然有序之后,就采用二分插入排序算法。
这样的混合排序算法,相对单纯的插入排序,保证了最好条件下时间代价最低,也减小了一般情况下的时间代价。

p.s.
写完之后查阅Python的文档,发现sort采用的是混合(hybrid)排序,规模小的时候采用binary insertion,规模大的时候采用samplesort(据说是quicksort的一个变种,我没接触过,汗….)

分享到:
评论

相关推荐

    yii2实现 上一篇,下一篇 功能的代码实例

    最近做了简答的文章详情页面,需要在页面底部加入上一篇,下一篇 按钮,分析了下,最基本需要有文章的标题和id(作为参数). 开始想的是当前的id加减1,但考虑到如果部分id丢失就不对了,于是分别查询比当前id大和小的记录...

    C#编程-提高篇

    然而对于接受类型T 的泛型方法Sort()需要一个比较方法,其两个参数的类型是T ,if 比较的返回类型是布尔类型。这个方法可以从Func, T2 , TResult>委托中引用,其中T1 和T2 的类型相同:Func, T , bool>。 给Sort...

    shuffle的关键阶段sort(Map端和Reduce端)源码分析

    今天小编就为大家分享一篇关于shuffle的关键阶段sort(Map端和Reduce端)源码分析,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

    SparkSQL源码分析之PhysicalPlan到RDD的具体实现

    接上一篇文章SparkSQLCatalyst源码分析之Physical Plan,本文将介绍PhysicalPlan的toRDD的具体实现细节:我们都知道一段sql,真正的执行是当你调用它的collect()方法才会执行Spark Job,最后计算得到RDD。SparkPlan...

    c程序设计习题参考(谭浩强三版)习题参考解答

    7.10有一篇文章,共有3行文字,每行有80个字符。要求分别统计出其中英文大写字母,小写字母,数字,空格以及其它字符的个数。 41 7.11打印以下图案: 42 7.12有一行电文,已按下面规律译成密码: 43 7.13编一个程序...

    Python实现希尔排序算法的原理与用法实例分析

    本文实例讲述了Python实现希尔排序算法的原理与用法。分享给大家供大家参考,具体如下: 希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入...(插入排序可参考前面一篇Python插入排序算法) Pyt

    小白学 Python 数据分析(5):Pandas (四)基础操作(1)查看数据

    小白学 Python 数据分析(2):Pandas (一)概述 小白学 Python 数据分析(3):Pandas (二)数据结构 Series 小白学 Python 数据分析(4):Pandas (三)数据结构 DataFrame 引言 最近这个系列有段时间没更新,...

    低清版 大型门户网站是这样炼成的.pdf

    网上有高清版350M的。可以去下 http://115.com/file/be5gwid8 请于下载后 24H 内及时删除!请抱着学习的态度下载此资料。 总共900多页!!!!!!! 第1篇 技术篇 第1章 大型门户网站架构分析 3 1.1 大型门户...

    php网络开发完全手册

    4.3 关于引用的解释 67 4.3.1 对变量的引用 67 4.3.2 对函数的引用 68 4.3.3 引用的释放 68 4.4 小结 69 第5章 PHP中类的应用 70 5.1 PHP中OOP的应用 70 5.1.1 类简介 70 5.1.2 类的信息封装 71 5.1.3 静态类 71 5.2...

    C++ STL开发技术导引(第5章)

    第一篇 预备知识 第1章 C++编程技术 2 1.1 类和对象 2 1.2 类的继承 5 1.3 函数重载 5 1.4 访问控制 7 1.5 操作符重载 8 1.6 显式类型转换 9 1.7 异常处理 13 1.8 名字空间 17 1.9 友员函数 20...

    深入浅出Struts 2 .pdf(原书扫描版) part 1

    他还撰写了深入揭示Tomcat工作机理和设计理念的名著How Tomcat Works,并在多种权威出版物上发表过100多篇文章。 目录 第1章 Model 2应用程序 1 1.1 Model 2概览 1 1.2 带servlet控制器的Model 2 2 1.2.1 Product...

    C++ STL 开发技术导引(第6章)

    第一篇 预备知识 第1章 C++编程技术 2 1.1 类和对象 2 1.2 类的继承 5 1.3 函数重载 5 1.4 访问控制 7 1.5 操作符重载 8 1.6 显式类型转换 9 1.7 异常处理 13 1.8 名字空间 17 1.9 友员函数 20...

    C++ STL开发技术导引(第3章)

    第一篇 预备知识 第1章 C++编程技术 2 1.1 类和对象 2 1.2 类的继承 5 1.3 函数重载 5 1.4 访问控制 7 1.5 操作符重载 8 1.6 显式类型转换 9 1.7 异常处理 13 1.8 名字空间 17 1.9 友员函数 20...

    处理Apache日志的Bash脚本

    去年一年,我写了将近100篇网络日志。 现在这一年结束了,我要统计”访问量排名”,看看哪些文章最受欢迎。(隆重预告:本文结尾处将揭晓前5名。) 以往,我用的是AWStats日志分析软件。它可以生成很详细的报表,...

Global site tag (gtag.js) - Google Analytics