首先归并排序的原理就是将一个待排序的列表分成二等份,四等份,八等份。。。。直到每一份只有一个元素的时候,然后合并,合并的时候进行排序。听起来有点绕。。。不多说 上代码
def mergesort(alist):
print('spliting',alist)
if len(alist)>1:
mid = len(alist)>>1
left = alist[:mid]
right = alist[mid:]
mergesort(left)
mergesort(right)
i,j,k = 0,0,0
while i<len(left) and j<len(right):
if left[i]<right[j]:
alist[k] = left[i]
i+=1
else:
alist[k] = right[j]
j+=1
k+=1
while i<len(left):
alist[k] = left[i]
k+=1
i+=1
while j<len(right):
alist[k] = right[j]
k+=1
j+=1
print('merge',alist)
切分其实挺好理解的,从代码中看就是下面这段代码,先找到中点,然后将这段列表分成left和right两部分
mid = len(alist)//2
left = alist[:mid]
right = alist[mid:]
mergesort(left)
mergesort(right)
但是合并怎么理解呢,我们可以举个栗子运行一下这段归并排序的代码,看看结果如何,可以利用代码中的两个print输出看清楚他们是怎么归并的。
result = [12,34,11,5,31]
mergesort(result)
print(result)
这是我用于测试mergesort函数的例子,然后我们看看输出了什么。
spliting [12, 34, 11, 5, 31]
spliting [12, 34]
spliting [12]
merge [12]
spliting [34]
merge [34]
merge [12, 34]
spliting [11, 5, 31]
spliting [11]
merge [11]
spliting [5, 31]
spliting [5]
merge [5]
spliting [31]
merge [31]
我只截了一部分的结果,这部分结果说明的是切分的可视化
从图中可以看到归并排序是将一个列表分成了[12, 34]和[11, 5, 31],然后将[12, 34]分成[12]和[34],[11, 5, 31]分成[11]和[5,31],再将[5,31]分成[5],[31]。这样子就是将一个列表完完全全切分了。然后关键是怎么合并的呢?
下面就是合并的代码
i,j,k = 0,0,0
while i<len(left) and j<len(right):
if left[i]<right[j]:
alist[k] = left[i]
i+=1
else:
alist[k] = right[j]
j+=1
k+=1
while i<len(left):
alist[k] = left[i]
k+=1
i+=1
while j<len(right):
alist[k] = right[j]
k+=1
j+=1
这段代码其实很简单 就是比较left列表的元素和right列表的元素谁小,小的就装入alist列表中。如果left或者right列表其中一个被装没了(说明先装完的列表小的元素比较多,都装进了alist),那么剩下的left或者right列表就依次全部装入alist(剩下的left或者right列表一定是有序的,下面马上讲原因)。
下面来看看合并结果的可视化:
spliting [12, 34, 11, 5, 31]
spliting [12, 34]
spliting [12]
merge [12]
spliting [34]
merge [34]
merge [12, 34] #A
A处解释:在这里已经可以看到12和34已经合并了 虽然他们本来就是有序的。
再看11, 5, 31的合并
spliting [11, 5, 31]
spliting [11]
merge [11]
spliting [5, 31]
spliting [5]
merge [5]
spliting [31]
merge [31]
merge [5, 31]#B
merge [5, 11, 31]#C
B处解释:这里合并了5和31 虽然他们也原本就是有序的
C处解释:这里合并了[11],[5,31]这两个列表,利用的就是上面合并的那段代码,谁小谁到alist里边去,注意alist的角色在转换,在一个mergesort代里边alist是代表一段已经拍好序的列表,但是回溯到上一个mergesort代里边,此时的alist可能就变成了上一代mergesort的left或者right,比如这一代是[12,34],下一代就是[12],[34],此时[12]就是left,[34]就是right,合并了的alist就是[12,34],但是回溯到了上一代[12,34]就变成left了,相应的right就变成了排序好的[5,11,31],这就是为什么前面说每一个回溯回来的left都是排序好的,因为此时的left是在下一代中是排序好的alist列表。
C处的解释是归并排序合并的灵魂,如果能看懂的话,应该就深刻理解了归并了。