Python的sort()
之前學(xué)習(xí)第九章的排序小結(jié)的時候,對sort()排序方法不理解,因為括號里面帶了自定義的比較函數(shù)。
后來查手冊,才發(fā)現(xiàn)sort()里面本來就帶了這樣的參數(shù)。能夠自定義比較方法,確實很靈活。
不僅如此,在網(wǎng)上查到一個博客,作者不單停留在這表面,還查究了sort()的排序算法,確實有意思。
全文抄錄如下:
http://blog.donews.com/maverick/archive/2006/07/09/951101.aspx
學(xué)習(xí)筆記:Python的排序
Python語言內(nèi)置了sort方法,可以很方便地對某個List進(jìn)行排序:
L = [6, 5, 1, 3, 4, 2]
L.sort()
print L
---------- Run Python Program ----------
[1, 2, 3, 4, 5, 6]
某些時候,我們希望按照自己定義的排序規(guī)則來排序(例如,按關(guān)鍵詞的權(quán)重排序,按人的年齡排序,等等)。在Java語言中,我們可以自定義Comparator來實現(xiàn),Python中也提供了類似的辦法。
若List中每個元素都是2-tuple,tuple中第一個元素為String類型的keyword,第二個元素為該字符串對應(yīng)的權(quán)重(int類型),希望按照權(quán)重排序(從高到低),則可以這樣:
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
可以看到,每次調(diào)用my_cmp,E1依次是List中的第2、3、4……直到最后一個元素,可以肯定sort不是采用的分治法(devide-and-conqure)
看 前三次調(diào)用,可以發(fā)現(xiàn)sort采用的是典型的插入排序——也就是說,將新元素插入已排序部分的合適位置,查找位置時采用的似乎是從后向前線形探察的辦法。 從元素6開始,新元素不再直接與已排序部分的最后元素比較,而是先與中間值比較,采用二分檢索探察合適位置,這樣,可以把時間代價從n縮小到 log(n)。
至此,我們可以認(rèn)為,built-in的sort方法,采用的是“二分法插入排序”(binary insertion)的算法。
為了檢測這個結(jié)論,可以輸入一個已排序的數(shù)組,看看結(jié)果。
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
結(jié)果發(fā)現(xiàn),比較的次數(shù)非常少,插入每個元素的時候,只會與它之前緊鄰的元素比較,而不是二分檢索。這真是個有意思的現(xiàn)象。
改一改程序
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
可以看到,在數(shù)字8以前,List中的元素都是有序的,于是sort算法也只比較欲插入元素和已排序序列的最后一個元素;一旦發(fā)現(xiàn)輸入序列不是自然有序之后,就采用二分插入排序算法。
這樣的混合排序算法,相對單純的插入排序,保證了最好條件下時間代價最低,也減小了一般情況下的時間代價。
p.s.
寫完之后查閱Python的文檔,發(fā)現(xiàn)sort采用的是混合(hybrid)排序,規(guī)模小的時候采用binary insertion,規(guī)模大的時候采用samplesort
總結(jié)
以上是生活随笔為你收集整理的Python的sort()的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 打印不换行
- 下一篇: Python: How to Sort