归并排序(Merge sort)
定义##
归并排序是一种递归算法,可以将列表连续分成两半。 如果列表为空或只有一个元素,则按定义(基本情况)已是排序列表。 如果列表有多个元素,我们拆分列表并在两半上递归调用合并排序。 一旦这两半部分排序完毕,就会执行称为合并的基本操作。 合并是获取两个较小的排序列表并将它们组合成一个排序的新列表的过程。
代码实现##
def merge_sort(a_list):
print('Splitting ', a_list)
if len(a_list) <= 1:
return a_list
mid = len(a_list) // 2
left = merge_sort(a_list[:mid])
right = merge_sort(a_list[mid:])
return merge(left, right)
def merge(left, right):
l, r = 0, 0
result = []
while l < len(left) and r < len(right):
if left[l] < right[r]
result.append(left[l])
l += 1
else:
result.append(right[r])
r += 1
result += left[l:]
result += right[r:]
print('Merging', result)
return result
代码解读##
merge_sort方法是一个递归函数,我们将整个列表折半拆分成左右两个部分,并分别对左右两个部分进行合并排序操作(递归调用merge_sort)。然后返回对排序好了的两个部分进行归并的结果(merge函数)。merge函数的功能就是将左右两个子列表归并成一个。
总结##
归并排序是一种稳定的排序算法,原因是折半拆分首先不改变相等元素的相对位置,其次在归并的时候,我们对大小比较可以进行有效的控制,如merge方法中的if left[l] < right[r]。
归并排序的算法时间复杂度分析:首先是折半拆分,由二分查找算法可知,若列表长度为n,则需要花费\(\log_2n\)的次数拆分。然后是归并操作,长度为n的列表需要n次归并,则总的时间复杂度为\(O(n\log_2n)\)。
值得注意的是,归并操作需要额外开辟内存以提供临时列表。比较耗内存,但效率高且稳定。改进归并排序在归并时先判断前段序列的最大值与后段序列最小值的关系再确定是否进行复制比较。如果前段序列的最大值小于等于后段序列最小值,则说明序列可以直接形成一段有序序列不需要再归并,反之则需要。所以在序列本身有序的情况下时间复杂度可以降至O(n)。