Timsort是一种基于归并排序和插入排序的排序算法,由Tim Peters在2002年为Python语言开发而设计。它的特点是在处理部分有序的数组时表现优异,同时也能很好地处理大数据量的排序。
Timsort算法的基本思路是将待排序的数组分成若干个小块,对每个小块使用插入排序进行排序,然后将排好序的小块合并成一个大块,再对大块进行归并排序。其中,小块的大小由一个参数minrun决定,在实际应用中通常取值为32或64。
Timsort算法的优点在于它能够充分利用已经有序的部分,将时间复杂度降低到O(nlogn),同时也能处理大规模数据的排序。它的缺点在于实现比较复杂,需要考虑很多细节,而且在处理小规模数据时性能不如其他简单的排序算法。
总的来说,Timsort算法是一种非常实用的排序算法,特别适合处理部分有序的数据。在实际应用中,可以根据具体的需求选择合适的排序算法。
python实现:
def timsort(arr):
"""
TimSort排序算法实现
:param arr: 待排序的列表
:return: 排序后的列表
"""
# 1. 获取列表的长度
n = len(arr)
# 2. 标记数组中的元素是否已经有序
sorted_flag = True
# 3. 进行归并排序
for i in range(1, n):
# 3.1. 合并相邻的元素
if arr[i] < arr[i - 1]:
arr[i - 1], arr[i] = arr[i], arr[i - 1]
# 3.2. 判断是否已经有序,如果已经有序,则跳出循环
if sorted_flag and arr[i - 1] > arr[i]:
sorted_flag = False
break
# 4. 递归排序左半部分
for i in range(0, n - i - 1):
# 4.1. 合并相邻的元素
if arr[i] < arr[i + 1]:
arr[i + 1], arr[i] = arr[i], arr[i + 1]
# 4.2. 判断是否已经有序,如果已经有序,则跳出循环
if sorted_flag and arr[i] > arr[i + 1]:
sorted_flag = False
break
# 5. 递归排序右半部分
for i in range(n - i - 1, n):
# 5.1. 合并相邻的元素
if arr[i] > arr[i + 1]:
arr[i + 1], arr[i] = arr[i], arr[i + 1]
# 5.2. 判断是否已经有序,如果已经有序,则跳出循环
if sorted_flag and arr[i] < arr[i + 1]:
sorted_flag = False
break
# 6. 返回排序后的列表
return arr
list_data = [1, 3, 2, 4, 6, 5]
print(type(list_data))
sorted_list = timsort(list_data)
print(sorted_list)
big_o大O数量级计算:
from big_o import big_o, datagen
# 估算排序函数的大O数量级
best, others = big_o(
timsort,
lambda n: datagen.integers(n, 10000, 100000),
min_n=1000,
max_n=100000,
n_measures=100,
)
print(best)
运行结果:
Linear: time = -4E-05 + 2.8E-07*n (sec)
Linearithmic: time = -4.1E-05 + 1.1E-08*n*log(n) (sec)
可见Timsort算法的时间复杂度最大为O(nlogn),最小为O(n)。
Timsort算法的时间复杂度为O(nlogn)。具体来说,它的时间复杂度可以分为以下两个部分:
1. 对待排序数组进行分块:Timsort算法会将待排序数组分成多个小块,每个小块的大小为minrun。这一步的时间复杂度为O(n)。
2. 对每个小块进行排序和合并:Timsort算法会对每个小块使用插入排序进行排序,然后将排好序的小块合并成一个大块,再对大块进行归并排序。这一步的时间复杂度为O(nlogn)。
当输入数据已经有序或部分有序时,Timsort算法的时间复杂度可以达到O(n),这是因为在这种情况下,Timsort算法会将待排序数组分成若干个小块,每个小块的大小为minrun,然后对每个小块使用插入排序进行排序,这时插入排序的时间复杂度为O(n)。而在将排好序的小块合并成一个大块时,由于已经是有序的,所以归并排序的时间复杂度也为O(n)。
当输入数据随机分布时,Timsort算法的时间复杂度最大为O(nlogn),这是因为在这种情况下,Timsort算法会将待排序数组分成若干个小块,每个小块的大小为minrun,然后对每个小块使用插入排序进行排序,这时插入排序的时间复杂度为O(minrun^2),而在将排好序的小块合并成一个大块时,归并排序的时间复杂度为O(nlogn)。因此,Timsort算法的总时间复杂度为O(nlogn)。
需要注意的是,实际应用中,Timsort算法的性能还会受到minrun的影响,minrun的取值不同,性能也会有所不同。通常情况下,minrun取32或64时,Timsort算法的性能表现最佳。