归并排序的思想:
对集合的排序,可以看成他们子集合的分别排序,然后把各个有序的子集合合并成有序的全集,这里一般把原集合尽可能的均分为2个子集合。
可以看出这里有两个工作量,一是把原数组不断的对半切,直到子问题足够小可以直接解出,二是把两个有序的数组合并成一个有序的数组。
def MergeSort(arr,N):
# 递归出口,出口需要返回当前的那个数
if N == 1:
return arr
# 以下当作某一层的处理
middle = N //2
# 获取待排序的两个已排序的数组
left_list = MergeSort(arr[:middle],len(arr[:middle]))
right_list = MergeSort(arr[middle:],len(arr[middle:]))
# 如下是针对两个已排序的数组合并成一个有序数组的排列方法,为最基本的双针模型
i ,j =0,0
result =[]
while i < len(left_list) and j < len(right_list):
if left_list[i] <= right_list[j]:
result.append(left_list[i])
i +=1
else:
result.append(right_list[j])
j += 1
result += left_list[i:]
result += right_list[j:]
# 返回已排序的结果,用于上一层获取待排序的有序数组
return result
我们想一下可以发现,对半切这个操作可以省略掉,对半切是为了切成大小为1的肉丁,但是数组本来就是已经切好了的,那我们一个直接开始合并的操作,两两合并,四四合并,…
def MergeSort_iteration(arr):
# 把一个数组arr[left:mid+1]和arr[mid+1:right+1]排成一个有序的序列,最后结果还是在
# arr里
def sorting_two_sorted_arr_in_place(arr,left,mid,right):
left_list = arr[left:mid+1]
right_list = arr[mid+1:right+1]
i ,j =0,0
result =[]
while i < len(left_list) and j < len(right_list):
if left_list[i] <= right_list[j]:
result.append(left_list[i])
i +=1
else:
result.append(right_list[j])
j += 1
result += left_list[i:]
result += right_list[j:]
arr[left:right+1] = result[:]
# 双针模型自然合并排序
# 最外面的大的指针,1,2,4,8,16,32...,直到大于len(arr)
cur_size = 1
# 终止条件为超过了数组长度,前半部分为2的i次方,后半部分为2的i次方到end
while cur_size < len(arr):
# 内部循环,用于更新每一块的顺序,只要一个left指针就可以更新每一个局部
left = 0
# 截至条件同样是left越界
while left < len(arr)-1:
# mid的位置,-1为数组是从0开始,简单分析一个实例就明白了
mid = left + cur_size -1
# right的位置,一般情况下是mid + cur_size,同样不能越界,越界时区len(arr)-1
right = (mid + cur_size,len(arr)-1)[mid + cur_size>len(arr)-1]
# 把制定区域的数排列有序
sorting_two_sorted_arr_in_place(arr,left,mid,right)
# 更新下一块,每一个固定cur_size循环里面的步长为2倍cur_size
left += 2*cur_size
# 更新外部循环的步长
cur_size *=2
return arr
运行结果
arr = [7,3,66,33,22,66,99,0,1]
print(arr)
print(MergeSort(arr,len(arr)))
print(MergeSort_iteration(arr))
[7, 3, 66, 33, 22, 66, 99, 0, 1]
[0, 1, 3, 7, 22, 33, 66, 66, 99]
[0, 1, 3, 7, 22, 33, 66, 66, 99]