TimSort

rilak

Abstract


Performance


Algorithm


...好像跟Python無關


wiki 說

TimSort

=

Adaptive

Merge Sort



Worst O(NlgN)

Best O(N)

平均 O(NlgN)



...很普通啊




這麼潮的演算法

為什麼沒有佔領全世界?



今天唯一的重點

Performance



對於隨機資料

期望複雜度 O(N lg N)



Worst Case 不會太差


越接近

Ordered data

(包含Reverse Case)

O(N)


Best Case 很猛




常數?

我都放在Object Comparison那了

While we're willing to endure small per-merge overheads, per-comparison overheads are a different story.




Comparison

比較很貴




跟排序的操作相對來說



1. 搬移物件 or 複製物件

關於指標的操作 Only 一步`

2. 比較兩個物件

首先確定類別 -> 找compare方法 -> 沒有的話還要比較blabla...




都是物件的錯



Java SE7

array : QuickSort

object : TimSort




Algorithm


前情提要


在Worst Case下

O(NlgN)是最佳狀況


所以我們不要求random時多好


不要退化

O(N) -> O(NlgN)


1.利用已經存在的排序

2.減少Comparison


對於已經排序過的資料

為一個單位 run





所以已經排好的資料

本身就是一個 run


排序結束


But...

[...   6 7 8 9 10 1 2 3 4 5   ...] 


當我們要合併兩個 run

看起來很漂亮可以接在一起


run1 = [1 2 3 4 5]

run2 = [6 7 8 9 10]


Merge Sort說

我們來比較第一個元素吧



run1 [1 2 3 4 5]

run2 [6 7 8 9 10]

結果 = [1]



run1 [1 2 3 4 5]

run2 [6 7 8 9 10]

結果 = [1 2]



run1 [1 2 3 4 5]

run2 [6 7 8 9 10]

結果 = [1 2 3]



run1 [1 2 3 4 5]

run2 [6 7 8 9 10]

結果 = [1 2 3 4]



run1 [1 2 3 4 5]

run2 [6 7 8 9 10]

結果 = [1 2 3 4 5]


...可是...

run1 = [101 ... 200]

run2 = [1 2 3 ... 100]


100 次比較





比較是很貴的




Gallop (v.) 馳騁


// Tim真的很愛運動...



俗稱

倍增搜尋法

Exponential Search

A = [101 102...200]

B = [1 2 3 4 5...100]


A[0] > B[0] 

A[0] > B[1]

A[0] > B[3]

A[0] > B[7]

A[0] > B[15]

...

A[0] > B[2**n-1]

A[0] <= B[2**(n+1)-1]


A[0] > B[2**(n-1)-1]

A[0] <= B[2**n-1]


left = 2**(n-1)-1

right = 2**(n)-1


Binary Search




比較次數

O(N) -> O(lgN)





直接做Binary Search?

run1 = [1 3 5 7 9...2N+1]
run 2 =[0 2 4 6 8...2N]

O(N) -> O(NlogN)

合併run的順序?


把發現的Run丟進Stack

保證最後三個元素

[..... A B C]

A > B+C

B > C


考慮極端的狀況


A = B + C


[... 64  32  16  8  4  2  1]

2^n 成長!!

常出現在 run 的長度很短的Case!


1. Stack不會太大

Python意外地注重空間使用...


2. 必免規模太多的run馬上合併

Merge會需要大量移動,效益又不高


最爛差不多

Merge Sort 的複雜度



Conclusion


利用已存在的遞增run

我相信真實世界的資料不會完全是Random的

有效率的合併沒有交叉的runs

Exponential Search 同時保證 linear 跟 Binary 的效率 

用stack保持run的長度指數成長

(同時保證效率跟Stack大小)

...偷偷省略的部分...


1. 當找到的run太小的話

合併太小的run會讓Compare增加
小範圍做Binary Insertion Search
然後還要討論怎樣算太小...

2.一開始不會直接做gallop

如果資料是random的
一直用gallop會輸給linear search



講到這邊

好像沒什麼用



有助於排序的資料?






1 % 雜質

10倍速度


快相當於省一個 log N了




不適合排序的資料?



Random的資料

重複的元素太多

Gallop跟Run的長度都會被限制
samplesort's special cases
  for extreme partial order are appreciated by real users

Recap


物件的移動 快於 物件的比較


Partial Ordered 會加速 Sort


Exponential Search



Ending

特別感謝
果凍
Timsort的Tim
Taipei.py的Tim

TimSort

By rilak1328

TimSort

  • 2,555