插入、希尔、归并排序算法, python编写

  • 插入排序:

其排序时间复杂度为O(n^{2}),它在待排列表中较低的一端维护一个有序的子列表,并逐个将每个新元素‘插入’这个子列表中。

nums = [54,26,93,17,77,31,44,55,20]
for i in range(1,len(nums)):
    currentvalue = nums[i]
    position = i
    while position>0 and currentvalue<nums[position-1]:
        nums[position] = nums[position-1]
        nums[position-1] = currentvalue
        position -=1
    nums[position] = currentvalue
print(nums)

结果:
[17, 20, 26, 31, 44, 54, 55, 77, 93]

在最坏的情况下,插入排序算法的比较是前n-1个整数之和(1+2+3+...+n-1),对应的复杂度为O(n^{2})

在最好的情况下(列表已经有序),每一论只比较一次(1+1+1.....),对应的复杂度为O(n)

所以,当插入一个新元素,且原有列表已经有序的情况下,插入排序很有效率。

  • 希尔排序:

希尔排序也称"递减增量排序",它对插入排序做了改进,将列表分成数个子列表,并对每一个子列表应用插入排序。如何切分列表是希尔排序的关键(并不是连续切分,而是使用增量i(有时称作为步长),选取所有间隔为i的元素组成子列表)

def gapinsertionsort(alist, start, gap):
    for j in range(start+gap,len(alist),gap):#以最小元素为为最小端进行插入排序
        position = j
        currentvalue = alist[position]
        while position > start and alist[position] < alist[position-gap]:
            alist[position] = alist[position-gap]
            alist[position-gap] = currentvalue
            position -=gap
        alist[position] = currentvalue

nums = [54,26,93,17,77,31,44,55,20]
iter = len(nums)//2  #第一次分成iter个子列表
while iter > 0:
    for startposion in range(iter):
        gapinsertionsort(nums , startposion, iter)#对每个子列表进行插入排序
    iter //=2 重复划分子列表,直到子列表为1
print(nums)

结果:
[17, 20, 26, 31, 44, 54, 55, 77, 93]

希尔排序每一次都是对子列表进行了一次插入排序,也就是说每一轮的遍历都生成了"更有序"列表。它的最大复杂度为O(n^{2})

  • 归并排序

归并排序采用的是分治策略。它是一种递归算法,每次将一个列表一分为二。如果列表为空或者只有一个元素,那么它就变得有序了。当两个部分都有序时,就进行归并(将两个较小的有序列表归并为一个有序列表的过程)这一基本操作。如图1所示:

该图截选于<<大话数据结构>>

递归版本:

def mergesort(alist,L,R):
    print('spliting', alist[L:R + 1])#打印每一次递归切分的子列表
    if L<R:#设置一个递归结束的条件
        mid=L+((R-L)>>1)#获取子列表中的中键
        mergesort(alist,L,mid)#对左部分排序
        mergesort(alist,mid+1,R)#对右部分排序
        merge(alist,L,mid,R)#将有序的两个子列表合并在一起
def merge(alist,L,mid,R):
    r=mid+1
    l=L
    temp=[]
    while l<=mid and r<=R:#先对两个子列表进行比对,把小指添加到temp数组,其中必有一个子列表被遍历完
        if alist[l]<alist[r]:
            temp.append(alist[l])
            l+=1
        else:
            temp.append(alist[r])
            r+=1
    #判断还有哪一个子列表没有遍历完,将剩余的元素添加到temp数组中
    while l<=mid:
            temp.append(alist[l])
            l+=1
    while r<=R:
            temp.append(alist[r])
            r+=1
    #将temp数组中的值,赋给原素组中去
    alist[L:R+1]=temp
    print("merging",alist[L:R+1])#打印递归以后merge的过程
#获取一个数组,进行排序。
nums=list(map(int,input().split()))
print(nums)
mergesort(nums,0,len(nums)-1)
print(nums)

整个结果图也是整个递归以及merge的过程图,应该来说是便于理解的。spliting表示二分列表的过程,merging表示合并两个子列表的过程

复杂度分析:由图一所示,当列表的长度为n时,能切分log n次,每一次需要进行n次操作,所以,时间复杂度为O(n*logn)

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值