zoukankan      html  css  js  c++  java
  • Python的内建sort方法

    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的一个变种,我没接触过,汗….)



    转载自:http://blog.donews.com/maverick/archive/2006/07/09/951101.aspx


    Meet so Meet. C plusplus I-PLUS....
  • 相关阅读:
    Hibernate之onetoone单向外键关联Annotation
    Server2008IIS7设置引用http://www.cnblogs.com/goldnet/archive/2008/07/11/1240685.html
    wcf exceptionaction
    性能测试中考虑时间(Thinking Time)的计算方法 http://developer.51cto.com/art/200807/87478.htm
    字节流的比较
    MemorySteam读取的问题Seek方法
    C# 参考之方法参数关键字:params、ref及out 引用http://www.cnblogs.com/hunts/archive/2007/01/13/619620.html
    Equal使用的注意点
    assembly load and unload
    CreateInstance数组传递
  • 原文地址:https://www.cnblogs.com/iplus/p/4467446.html
Copyright © 2011-2022 走看看