归并排序
1.了解归并
假设现在的列表分两段有序,如何将其合成一个有序列表
上面这张图,按照虚线分开,分成两个有序列表,设计一个代码变成一个有序
【解题思路】
两箭头代表两段有序数列的第一个元素
两端比大小,哪个数小就把那个数放进新列表,以此类推
当某一边没有数时,将其余数依次存入列表中
【归并代码实现】
def merge(li,low,mid,high):
#列表,最开始的值,中间值(第一个有序列表的最后一位),最后面的值
#将两个有序列表的开头标记出来
i=low
j=mid+1#第二段有序数列的开头
list_1=[]
while i<=mid and j<=high:#限制条件(开头小于结尾)两边都有数
if li[i] < li[j]:
list_1.append(li[i])
i+=1
else:
list_1.append(li[j])
j+=1
#while执行完成,,肯定有一部分没数了
while i<=mid:#左列表还有数
list_1.append(li[i])
i+=1
while j<=high:#右列表还有数
list_1.append(li[j])
j+=1
#再将list_1里的数放回li中
li[low,high+1]=list_1
2.归并排序——使用归并
【解题步骤】
1、分解:将列表越分越小,直至分成一个元素
2、终止条件:一个元素是有序的
3、合并:将两个有序列表归并,列表越来越大
【代码实现】
#归并函数
def merge(li,low,mid,high):
#列表,最开始的值,中间值(第一个有序列表的最后一位),最后面的值
#将两个有序列表的开头标记出来
i=low
j=mid+1#第二段有序数列的开头
list_1=[]
while i<=mid and j<=high:#限制条件(开头小于结尾)两边都有数
if li[i] < li[j]:
list_1.append(li[i])
i+=1
else:
list_1.append(li[j])
j+=1
#while执行完成,,肯定有一部分没数了
while i<=mid:#左列表还有数
list_1.append(li[i])
i+=1
while j<=high:#右列表还有数
list_1.append(li[j])
j+=1
#再将list_1里的数放回li中
li[low:high+1]=list_1
def merge_sort(li,low,high):
#终止条件 只有一个元素
if low<high:#至少有两个,递归终止条件(只剩一个的时候)
mid=(low+high)//2#二分查找中间值
merge_sort(li,low,mid)#递归左边,左边排序
#print(li[low:high+1])
merge_sort(li,mid+1,high)#递归右边,右边排序
#print(li[low:high+1])
merge(li,low,mid,high)
#print(li[low:high+1])
li=list(range(16))
import random
random.shuffle(li)
print(li)
merge_sort(li,0,len(li)-1)
print(li)
【运行结果】
我打印了每次递归后的结果和归并后的结果。
#递归
[0, 13]
[0, 13]
[4, 12]
[4, 12]
[0, 13, 4, 12]
[0, 4, 12, 13]
[3, 2]
[2, 3]
[8, 11]
[8, 11]
[2, 3, 8, 11]
[2, 3, 8, 11]
[0, 4, 12, 13, 2, 3, 8, 11]
[0, 2, 3, 4, 8, 11, 12, 13]
[6, 10]
[6, 10]
[9, 1]
[1, 9]
[6, 10, 1, 9]
[1, 6, 9, 10]
[7, 5]
[5, 7]
[15, 14]
[14, 15]
[5, 7, 14, 15]
[5, 7, 14, 15]
[1, 6, 9, 10, 5, 7, 14, 15]
[1, 5, 6, 7, 9, 10, 14, 15]
[0, 2, 3, 4, 8, 11, 12, 13, 1, 5, 6, 7, 9, 10, 14, 15] #递归
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] #归并函数
时间复杂度O(nlogn)