算法-排序-归并排序
文章目录
一、归并排序介绍
1.1、归并排序定义
归并排序(Merging Sort):归并的含义是将两个或两个以上的有序表组合成一个新的有序表。
1.2、2-路归并排序
假设初始序列含有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,如此重复,直至得到一个长度为n的有序序列位置。这种排序方法称为2-路归并排序。
- 2-路归并排序中的核心操作是将一维数组中前后相邻的两个有序序列归并为一个有序序列。
二、归并排序操作
下面已 2-路归并排序为例
2.1、归并排序整体操作思路
2.2、归并排序归并操作思路
如何将两组有序组组合成一个新的有序表
-
第一步, 初始化时,标记列表起始位置为start,中间位置middle,结束位置end。 设置两个标签low=start和high=middle + 1,用于遍历列表的两个部分。如下图所示
-
第二步,假设是升序,比较low和high对应的值。如下图所示
-
第三步,将对应小的值放入一个临时列表,如下图所示
-
第四步,将放入值对应low或high位置向后移动,比如这里是high对应值小,high向end方向移动一个。如下图所示。
-
第五步,检查low的位置是否大于middle 和 high位置是否大于 end位置,没有的话继续比较low和high对应值。将小的值插入临时列表。如下图所示。
-
第六步,重复第四步、第五步,如下图所示
-
第七步,当high大于end 或 low大于middle 代表有一部分遍历完成,只需要将未遍历完的,放入临时列表
-
第八步,当high和low都遍历完,代表列表两个部分已经归并完成。最后将归并后的列表替换原理列表[start: end+1]
2.2、归并排序操作动画
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
三、归并排序代码实现
def merge(_list, is_ascending, start, middle, end):
"""
将列表的两个部分进行归并
:param _list:
:param is_ascending: 是否升序,True为升序,False为降序,默认为True
:param start: 起始位置
:param middle: 中间位置
:param end: 结束位置
:return:
"""
list_tmp = [] # 临时列表, 用于保存归并后的列表
low = start # low 表示记录当前遍历序列地位区间的位置
high = middle + 1 # high 表示记录当前遍历序列高位区间的位置
while low <= middle and high <= end:
# 当前序列低位区间与高位区间都没有遍历完时
if is_ascending:
# 升序
# 将小的值保存到归并后的列表,并让low向middle方向移动,或让high向end方向移动
if _list[low] <= _list[high]:
list_tmp.append(_list[low])
low += 1
else:
list_tmp.append(_list[high])
high += 1
else:
# 降序
if _list[low] >= _list[high]:
list_tmp.append(_list[low])
low += 1
else:
list_tmp.append(_list[high])
high += 1
while low <= middle:
# 表示高位区间的元素已全部保存到归并后的列表
list_tmp.append(_list[low])
low += 1
while high <= end:
# 表示低位区间的元素已全部保存到归并后的列表
list_tmp.append(_list[high])
high += 1
# 将归并后的列表覆盖原列表
_list[start: end + 1] = list_tmp
def merge_recursion(_list, is_ascending, start, end):
"""
归并递归
:param _list: 待排序的列表
:param is_ascending: 是否升序,True为升序,False为降序,默认为True
:param start: 列表的起始位置
:param end: 列表的结束位置
:return: 已排好序的列表
"""
if start < end:
# 代表序列的起始位置小于结束位置,即序列至少有两个元素
# 将序列拆分成两个部分,获取中间位置
middle = (start + end) // 2
# 将序列拆分成两个部分继续进行归并排序递归,直到最小元素个数
merge_recursion(_list, is_ascending, start, middle)
merge_recursion(_list, is_ascending, middle + 1, end)
# 将序列拆分的两个部分进行归并合并
merge(_list, is_ascending, start, middle, end)
return _list
def merge_sort(_list, is_ascending=True):
"""
归并排序(2-路归并排序),递归形式
:param _list: 待排序列表
:param is_ascending: 是否升序,True为升序,False为降序,默认为True
:return: 已排序的列表
"""
return merge_recursion(_list, is_ascending, 0, len(_list) - 1)
if __name__ == '__main__':
l1 = [49, 38, 65, 97, 76, 13, 27, 49]
l2 = merge_sort(l1, False)
print(l2)
pass
输出结果:
[97, 76, 65, 49, 49, 38, 27, 13]
四、归并排序复杂度
归并排序需要和待排记录等数量的辅助空间,空间复杂度O(n)
其时间复杂度为O(nlogn)
特定:稳定