归并排序的实现及其优化(递归法)

归并排序
一、思路(递归)

list = [a,b,c,d]

1、 递归过程

1、数组一分为2,list1 = [a,b] list2 = [c,d]

2、先确立递归项:分别对list1/list2做归并排序,此时可以假设左右子数组已经有序。

3、执行merge子过程,将list1/list2合并并使之有序。

3、在程序首部添加基准条件:当前候选数组长度为1,直接return,停止向下递归。

  • 约定

经典的归并排序,目标数组采用闭区间来标记,即[left,right],各标记定义如下:

数组长度 n=7

index    0    1    2    3    4    5    6
value    3    2    5  | 7    1    3    6
标记    left      mid                 right

注:n = 7
    left = 0
    right = n -1
    mid = right // 2
2、merge子过程
  • 思路

1、函数传入整个数组,要merge的子数组区间范围[left,mid],[mid+1,right]

2、做完整数组的切片 a=list[left,right+1]

3、设定内部指针i遍历子数组1,j遍历子数组2
指针k遍历赋值给完整数组

二、实现
from sort_helper import test_sort,random_array

def __merge(array, left, mid, right):
	temp = array[left:right+1]
	#新数组temp的左中右标记,充当常量
	n = len(temp)
	l = 0
	r = n-1
	m = l + (r -l) // 2
	#左数组标记i,右数组标记j,赋值外部循环标记k
	i = 0
	j = m + 1
	#遍历【0,n)即整个数组长度,每次确定一个下标应该赋值的元素并完成赋值操作
	k = 0 
	while k < n:
		#2、定义判断条件,防越界;循环的次数是由n确定的,不存在i,j同时越界的情况
		if i > m:
			array[k + left] = temp[j]
			j += 1
		elif j > r:
			array[k + left] = temp[i]
			i += 1
		#1、判断两个子数组当前位置的值,并赋值给原数组array的对应位置,此处可能涉及到越界问题,所以循环主体开始之前要判断一下
		elif temp[i] < temp[j]:
			array[k + left] = temp[i]
			i += 1
		else:
			array[k + left] = temp[j]
			j += 1

		k += 1

#错误示范
def __merge1(array, left, mid, right):
	#错误1,开辟数组空间只针对一部分元素,而非整个数组
	temp = array[:]
	#错误2,left应该最后赋值为0,否则后两部相当于减0,无作用
	#错误3:内部端点就应该重新定义为l、r、mid;一旦否则array[k+left]无效果,因为left已变..
	left = 0
	mid = mid - left
	right = right - left
	n = right - left + 1
	i = 0
	j = mid + 1
	k = 0 
	while k < n:
		if i > mid:
			array[k + left] = temp[j]
			j += 1
		elif j > right:
			array[k + left] = temp[i]
			i += 1
		elif temp[i] < temp[j]:
			array[k + left] = temp[i]
			i += 1
		else:
			array[k + left] = temp[j]
			j += 1

		k += 1
	print(array)

#该私有函数需要左右下标
def __merge_sort(array, left, right):
	#3、添加基准条件,左右区间短点,相差1即可,即子数组长度为1
	if right -left <= 0:
		return
	#1、一分为二
	mid = left + (right -left) // 2 
	#2、左右分别归并排序,应该考虑到要添加基准条件了,否则无限递归
	__merge_sort(array, left, mid)
	__merge_sort(array, mid+1, right)
	#4、此时,array两个子数组都已有序,但整个数组却还无序,需要合并
	__merge(array, left, mid, right)

def merge_sort(array):
	#作为带外暴露的归并排序函数,不需要左右下标
	__merge_sort(array, 0, len(array)-1)

if __name__ == '__main__':
	array = random_array()
	test_sort('merge_sort', merge_sort, array)

三、优化
1、提前终止不必要的merge操作
def __merge_sort1(array, left, right):
	#3、添加基准条件,左右区间短点,相差1即可,即子数组长度为1
	if right -left <= 0:
		return
	#1、一分为二
	mid = left + (right -left) // 2 
	#2、左右分别归并排序,应该考虑到要添加基准条件了,否则无限递归
	__merge_sort1(array, left, mid)
	__merge_sort1(array, mid+1, right)
	#4、此时,array两个子数组都已有序,但整个数组却还无序,需要合并
	if array[mid] > array[mid+1]:
		__merge(array, left, mid, right)

def merge_sort1(array):
	#作为带外暴露的归并排序函数,不需要左右下标
	__merge_sort1(array, 0, len(array)-1)

2、使用插入排序优化
def __merge_sort2(array, left, right):
	if right -left <= 50:
		insert_sort(array, left, right)
		#必须要有return,否则无限递归
		return
	mid = left + (right -left) // 2 
	__merge_sort2(array, left, mid)
	__merge_sort2(array, mid+1, right)
	if array[mid] > array[mid+1]:
		__merge(array, left, mid, right)

def merge_sort2(array):
	__merge_sort2(array, 0, len(array)-1)
3、测试用例
if __name__ == '__main__':
	array = random_array()
	array1 = array[:]
	array2 = array[:]
	array3 = nearly_ordered_array(10000, 1)
	array4 = array3[:]
	array5 = array3[:]
	test_sort('merge_sort random_array', merge_sort, array)
	test_sort('merge_sort1 random_array', merge_sort1, array1)
	test_sort('merge_sort2 random_array', merge_sort2, array2)
	test_sort('merge_sort nearly_ordered_array', merge_sort, array3)
	test_sort('merge_sort1 nearly_ordered_array', merge_sort1, array4)
	test_sort('merge_sort2 nearly_ordered_array', merge_sort2, array5)

优化效果在有序性较强的情况下比较明显

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值