归并排序
一、归并排序的思想
1.主要思路
归并排序的思想是分而治之。
- 通常我们会把还有N个元素的列表,拆分成每个都包含N/2个元素的子列表
- 对俩个子列表递归调用并排序
- 合并俩个已经排好序的子列表
下图展示为归并排序的示意图
即采用分而治之的方法,简单地说就是在其长度一分为二 ,分为俩组列表。
二、Python代码详解展示
1.完整python代码
def merge(left,right):#分而治之,合拼列表
merged = []
i,j =0,0 #初始化为零
left_len,right_len =len(left),len(right)
while i < left_len and j < right_len:
if left[i] <= right[j]:
merged.append(left[i])
i += 1 # i = i + 1 让下标指向列表的下一个元素
else:
merged.append(right[j])
j += 1 # j = j + 1
if i < len(left):
merged.extend(left[i:])
if j < len(right):
merged.extend(right[j:])
# print(left,right,merged)
return merged
def merge_Sort(a):
if len(a) <= 1:
return a
middle = len(a) // 2
left = merge_Sort(a[:middle])
right = merge_Sort(a[middle:])
return merge(left,right)
if __name__ == "__main__":
a = [98, 23, 45, 14, 6, 67,33,42]
print(f"排序前:{a}")
a1 = merge_Sort(a)
print(f"排序后:{a1}")
2.程序拆分
列表合并部分
#################################################################
def merge(left,right):#分而治之,合拼两个列表,前提 前已经排好序
merged = [] #创建一个新的列表
i,j =0,0 #初始化为零, i为left的索引,j为right的索引 (为了合并)
left_len,right_len =len(left),len(right) #获取左右子列表的长度 (为了合并)
while i < left_len and j < right_len: #循坏归并左右子列表 (合并)
if left[i] <= right[j]: #左子列表元素小于等于右子列表,这里如果为 “ < ” 会不稳定,但不影响结果(合并)
merged.append(left[i]) # 追加子列表元素到merged 里(合并)
i += 1 # i = i + 1 让索引指向列表的下一个元素(合并)
else:
merged.append(right[j]) # 否则将right[i]的元素追加到列表merged里(合并)
j += 1 # j = j + 1 (合并)
if i < len(left): # 可有可无不影响程序,因为切边中已经处理了 ,其中有一个为空
merged.extend(left[i:]) #归并左子列表剩余元素,采用了切片[i:](从i开始到最后)
if j < len(right): # 可有可无不影响程序,因为切边中已经处理了 ,其中有一个为空
merged.extend(right[j:]) #归并右子列表剩余元素,采用了切片[j:](从i开始到最后)
# print(left,right,merged) #显示运算过程(准确的说是跟踪调试) 可有可无,不影响程序
return merged #将merged这个新的合并列表返回回去(返回,归并好的列表)
#######################################################
递归函数的创建
#############################################################
def merge_Sort(a): #创建一个递归函数
if len(a) <= 1: #空或者只有1个元素,直接返回列表merge_Sort(a)
return a
middle = len(a) // 2 #列表中间位置 (拆分和合并过程)
left = merge_Sort(a[:middle]) #切片a[:middle],(归并排序左子列表),执行merge_Sort (拆分和合并过程)
right = merge_Sort(a[middle:]) #切片a[middle:],(归并排序左子列表),执行merge_Sort (拆分和合并过程)
return merge(left,right) #调用上一个定义中def merge(left,right):的merge函数,将排好序的左右子列表合并 (拆分和合并过程)
if __name__ == "__main__":
a = [98, 23, 45, 14, 6, 67,33,42]
print(f"排序前:{a}")
a1 = merge_Sort(a)
print(f"排序后:{a1}")
#############################################################
4.程序jupyter运行结果
结果展示
三、归并排序分析
需要将列表一步步拆成子列表,有点类似与选择排序和冒泡排序的轮次。
1.好的情况
需要比较N/2次
2.最坏的情况
需要比较N次,归并排序需要至多 N l o g 2 N Nlog_2 N Nlog2N次比较
3.选择排序和冒泡排序、归并排序的次数比较
-
对与“选择排序”和“冒泡排序”他们的比较次数 ( N 2 / 2 ) − n (N^2/2 ) - n (N2/2)−n
-
归并排序的比较次数是: N l o g 2 N Nlog_2 N Nlog2N
-
归并排序的比较次数
N l o g 2 N Nlog_2 N Nlog2N 远远小于 ( N 2 / 2 ) − n (N^2/2 ) - n (N2/2)−n,选择排序”和“冒泡排序”的次数
从上述,我们可以知道归并排序的速度,远远快于选择排序和冒泡排序
四、总结
Python语言系统提供的排序算法:底层采用了一种归并排序算法实现
1.sort方法
a = [2,6,5,7,3]
a = sort() #默认升序排序
print(a) #输出[2,3,5,6,7]
a = [2,6,5,7,3]
a = sort(reverse = True) #降序排序
print(a) #输出[7,5,6,2,3]
2.python内置函数sorted
a = [2,6,5,7,3]
a = sorted(a) #降序采用sorted(a,reverse =True)
print(a) #输出[2, 6, 5, 7, 3]
print(b) #输出[2, 3, 5, 6, 7]
所以根据个人喜欢,看情况选择使用