归并排序
列表归并
一个列表分成两部分,这两部分是分别是有序的,但整个列表不是有序的。采用归并的方式让这个列表有序。
li = [2, 3, 6, 8, 1, 4, 5, 7] # 2,3,6,8有序; 1,4,5,7有序
# 实现归并
def merge(li, low, mid, high):
"""
两段有序列表的的合并
:param li:
:param low: 列表起始位置
:param mid: 分段处
:param high: 列表最后位置
:return: 合并好的有序列表
"""
i = low # 前段有序的哨兵
j = mid + 1 # 后段有序的哨兵
ltmp = []
while i <= mid and j <=high:
if li[i] < li[j]:
ltmp.append(li[i])
i += 1
else:
ltmp.append(li[j])
j += 1
# 退出上面while循环说明有一边已经结束
# 下面的两个while寻汗只有一会执行
while i <= mid:
ltmp.append(li[i])
i += 1
while j <= high:
ltmp.append(li[j])
j += 1
# 将排序好的列表在切回去
li[low: high+1] = ltmp
# 测试
li = [2, 3, 6, 8, 1, 4, 5, 7]
merge(li, 0, 3, len(li)-1)
print(li)
# output:
[1, 2, 3, 4, 5, 6, 7, 8]
上述归并的时间复杂度是:O(n)
归并排序
# 分解:将列表越分越小,直至分成一个元素。
# 终止条件:一个元素是有序的。
# 合并:将两个有序列表归并,列表越来越大。
代码实现
# -*- coding: utf-8 -*-
# created by X. Liu on 2020/3/15
import random
def merge(li, low, mid, high):
i = low # 前段有序的哨兵
j = mid + 1 # 后段有序的哨兵
ltmp = []
while i <= mid and j <=high:
if li[i] < li[j]:
ltmp.append(li[i])
i += 1
else:
ltmp.append(li[j])
j += 1
while i <= mid:
ltmp.append(li[i])
i += 1
while j <= high:
ltmp.append(li[j])
j += 1
li[low: high+1] = ltmp
def merge_sort(li, low, high):
"""
归并排序,递归思想
:param li:
:param low: 列表第一个索引值
:param high: 列表最后一个索引值
:return: None
"""
if low < high: # 至少两个元素
mid = (low + high) // 2
merge_sort(li, low, mid)
merge_sort(li, mid+1, high)
merge(li, low, mid, high)
# 测试
li = list(range(20))
random.shuffle(li)
print(li)
merge_sort(li, 0, len(li)-1)
print(li)
# output:
[2, 7, 13, 14, 4, 16, 15, 17, 12, 6, 0, 10, 8, 5, 3, 11, 19, 9, 18, 1]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
时间复杂度
# 时间复杂度:O(nlogn)
# 空间复杂度:O(n)
# python的排序sort()基于归并排序实现