zoukankan      html  css  js  c++  java
  • 排序算法:merge sort(python)

    基本原理

    merge sort就是用divide and conquer的方法来实现sort。
    它将一个要倍排序的序列,分成两个已经排好序的序列,在将他们的合并起来。

    在合并的时候,首先指针都在两个序列的最前端,然后比较大小,将符合的放入新的序列中,指针再后移,再进行相同的比较过程。

    错误的第一次实现

    错误示例!

    #merge sort
    def merge(L_l,L_r):
    	i = 0
    	j = 0
    	L_new = []
    	while i<len(L_l) and j<len(L_r):
    		if L_l[i] > L_r[j]:
    			L_new.append(L_l[i])
    			i += 1
    		elif L_l[i] < L_r[j]:
    			L_new.append(L_r[j]) 
    			j += 1
    		else:
    			L_new.append(L_r[j])
    			L_new.append(L_l[i])
    			i += 1
    			j += 1
    	print("L_new="+str(L_new))
    	return L_new
    
    def mergesort(L):
    	print("lenl="+str(len(L)))
    	if len(L) <= 1:
    		return L
    	else:
    		mid = len(L)//2 
    		print("mid="+str(mid))
    		L_sort = L[:]
    		lefthalf = L[:mid]
    		righthalf = L[mid:]
    		L_l = mergesort(lefthalf)
    		print("L_l done")
    		print("L_l="+str(L_l))
    		# mid = len(L)//2
    		print("mid2="+str(mid))
    		# L_sort = L[:]
    		L_r = mergesort(righthalf)
    		L = merge(L_l,L_r)
    		return L
    
    L = [1,5,6,3,7,8]
    mergesort(L)
    print(L)
    

    此方法错误,打印debug信息如下。

    L(1)=[1, 5, 6, 3, 7, 8]
    mid(1)=3
    lefthalf(1)=[1, 5, 6]
    righthalf(1)=[3, 7, 8]
    L(2)=[1, 5, 6]
    mid(2)=1
    lefthalf(2)=[1]
    righthalf(2)=[5, 6]
    L(3)=[1]
    L_l_after(2=[1]
    L(3)=[5, 6]
    mid(3)=1
    lefthalf(3)=[5]
    righthalf(3)=[6]
    L(4)=[5]
    L_l_after(3=[5]
    L(4)=[6]
    L_r_after(3=[6]
    L_new=[6]
    L_after(3=[6]
    L_r_after(2=[6]
    L_new=[6]
    L_after(2=[6]
    L_l_after(1=[6]
    L(2)=[3, 7, 8]
    mid(2)=1
    lefthalf(2)=[3]
    righthalf(2)=[7, 8]
    L(3)=[3]
    L_l_after(2=[3]
    L(3)=[7, 8]
    mid(3)=1
    lefthalf(3)=[7]
    righthalf(3)=[8]
    L(4)=[7]
    L_l_after(3=[7]
    L(4)=[8]
    L_r_after(3=[8]
    L_new=[8]
    L_after(3=[8]
    L_r_after(2=[8]
    L_new=[8]
    L_after(2=[8]
    L_r_after(1=[8]
    L_new=[8]
    L_after(1=[8]
    [1, 5, 6, 3, 7, 8]
    

    从这个里面可以看到,是merge出的问题,没有将两个全部加入。可以发现,是while循环没有做完出现的问题。因为前面的while结束后,可能还有剩余的部分没有加入,因此需要在写循环把之后的全部加入。

    更改后的代码如下:

    #merge sort
    
    def merge(L_l,L_r):
    	i = 0
    	j = 0
    	L_new = []
    	while i<len(L_l) and j<len(L_r):
    		if L_l[i] > L_r[j]:
    			L_new.append(L_l[i])
    			i += 1
    		elif L_l[i] < L_r[j]:
    			L_new.append(L_r[j]) 
    			j += 1
    		else:
    			L_new.append(L_r[j])
    			L_new.append(L_l[i])
    			i += 1
    			j += 1
    	while i < len(L_l):
    		L_new.append(L_l[i])
    		i += 1
    	while j < len(L_r):
    		L_new.append(L_r[j])
    		j += 1
    	# print("L_new="+str(L_new))
    	return L_new
    
    def mergesort(L,count):
    	count += 1
    	# print("L("+str(count)+")="+str(L))
    	if len(L) <= 1:
    		return L
    	else:
    		mid = len(L)//2 
    		# print("mid("+str(count)+")="+str(mid))
    		# L_sort = L[:]
    		lefthalf = L[:mid]
    		righthalf = L[mid:]
    		# print("lefthalf("+str(count)+")="+str(lefthalf))
    		# print("righthalf("+str(count)+")="+str(righthalf))
    		L_l = mergesort(lefthalf,count)
    		# print("L_l_after("+str(count)+"="+str(L_l))
    		L_r = mergesort(righthalf,count)
    		# print("L_r_after("+str(count)+"="+str(L_r))
    		L = merge(L_l,L_r)
    		# print("L_after("+str(count)+"="+str(L))
    		return L
    
    count = 0 
    L = [1,5,6,3,7,8]
    L_new = mergesort(L,count)
    print(L_new)
    

    此刻可以返回正确的结果。

    insert sort 与 merge sort的对比

    insert sort比merge sort 的优点在与内存。如果想要完成merge sort,那么需要一个theta(n)的auxiliary space(辅助空间),但是in place sort 只需要theta(1)的auxiliary space。因为merge sort需要复制左右两个序列然后把新的序列存入。

    为了解决这个问题,人们提出了in-place merge sort,但是running time会很差,为theta(n^2),因此并不是常用。

    时间复杂度

    为nlog(n),该过程可以用树来直观的看出。
    由merge sort的原理列出式子为:
    T(n) = 2T(n/2) + c*n
    我们可以通过一个recurrence tree来直观的看出其复杂度。

    在这里树里面,每级的叶子都有相同的量。

    下面一次为延伸,来使用树计算一些其他的式子的时间复杂度。
    例1: T(n) = 2T(n/2) + c

    在这种情况下,叶子是主导作用,因此时间复杂度以此计算。

    例2: T(n) = 2T(n/2) + c*n^2

    在这种情况下,根起主导作用。

  • 相关阅读:
    SQLite无法使用drop column删除表字段解决办法
    Selenium之自动发送163邮件(转自https://www.cnblogs.com/zhang-da/p/12230415.html)
    frp 内网穿透
    smart.supor.com
    python colorama模块
    nohup和&后台运行,进程查看及终止
    Beef搭建并通过Nginx绑定域名
    How to Install Ruby on CentOS/RHEL 7/6
    Linux环境下安装python3
    启用IIS Express SSL(Https)的注意事项
  • 原文地址:https://www.cnblogs.com/litingyu/p/9199502.html
Copyright © 2011-2022 走看看