插入排序及其Python实现 - Go语言中文社区

插入排序及其Python实现


插入排序

  插入排序每步将一个带排序的对象,按其关键码大小,插入到前面已经排好序的一组对象的适当位置上,知道对象全部插入为止。插入排序边插入边排序,子序列随时都是排好序的。
  插入排序一般分三步进行:
 (1)在R[1…i-1]中查找R[i]的插入位置; R[1..j].key < R[i].key< R[j+1..i-1].key
 (2)将R[j+1..i-1]中的所有记录均后移一个位置;
 (3)将R[i]插入到R[j+1]的位置上。
插入排序
  根据具体实现方法的不同可分为基于顺序查找的直接插入排序、基于折半查找的折半插入排序、基于链表存储的表插入排序、基于逐趟缩小增量的希尔排序

1.直接插入排序

  直接插入排序主要利用顺序查找实现在R[1..i-1]中查找R[i]的插入位置,是一种稳定的排序算法。具体做法:R[0]作为监视哨,从R[i-1]起向前进行顺序查找,寻找R[i]的插入位置;在查找过程中找到的关键字不小于R[i].key的记录,在查找的同时,实现记录向后移动,循环结束后可以直接插入R[i]。

[13, 6, 3, 31, 9, 27, 5, 11]
第 1 次: [【13】, 6, 3, 31, 9, 27, 5, 11]
第 2 次: [【6, 13】, 3, 31, 9, 27, 5, 11]
第 3 次: [【3, 6, 13】, 31, 9, 27, 5, 11]
第 4 次: [【3, 6, 13, 31】, 9, 27, 5, 11]
第 5 次: [【3, 6, 9, 13, 31】, 27, 5, 11]
第 6 次: [【3, 6, 9, 13, 27, 31】, 5, 11]
第 7 次: [【3, 5, 6, 9, 13, 27, 31】, 11]
第 8 次: [【3, 5, 6, 9, 11, 13, 27, 31】]

一般情况下,直接插入排序的时间复杂度为O(n2),空间复杂度为O(1)(监视哨R[0]占用1空间)
如果记录基本有序,则每次只需比较一次,将R[i]直接加入到有序序列中,最好情况下的事件复杂度为O(n)

def direct_insert_sort(R):
    num = len(R)
    print "第 1 次:", R[1:]
    for i in range(2, num):  # start sorting from the second record
        R[0] = R[i]
        if R[i-1] <= R[0]:
            R[i] = R[0]
        else:
            for t in range(i):  # find the place to insert R[i]
                j = i-t
                if R[j] > R[0]:
                    R[j+1] = R[j]  # R[j]记录后移
                if R[j-1] <= R[0]:
                    R[j] = R[0]  # 记录R[i]插入位置j
                    break
        print "第", i, "次:", R[1:]
    return R

2.折半插入排序

  折半插入排序是在直接插入排序的基础上改进的插入排序算法。R[1..i-1] 是一个按关键字有序的有序序列,则可以利用折半查找实现“在R[1..i-1]中查找R[i]的插入位置”,把原来位置上的元素向后顺移。
  在已形成的有序表中折半查找,比较的次数大大减少,全部元素的比较次数为O(nlog2n)。但由于移动次数并未减少,所以折半插入排序的时间效率依然为O(n2),空间效率仍为O(1),是一种稳定的排序算法。

def half_insert_sort(R):
    num = len(R)
    for i in range(2, num):
        R[0] = R[i]
        if R[i-1] <= R[i]:
            R[i] = R[0]
        else:
            # 找到位置m插入 R[i]
            low = 0
            high = i - 1
            while low <= high:  
                m = (high + low)/2
                if R[m] > R[0]:
                    high = m - 1
                else:
                    low = m + 1
            R[m+1:i+1] = R[m:i]  #R[m:i]记录后移
            R[m] = R[0]  # insert R[i] on the record m
    return R

  如果记录用链表结构存储,用直接插入排序无需移动元素,时间效率更高。但是链表结构无法进行折半查找。

3.希尔排序(缩小增量排序)

  希尔排序的基本思想是先将整个带排序记录序列分割成若干个子序列,分别进行直接插入排序,待整个序列中的记录”基本有序“时,在对记录进行一次直接插入排序。值得注意的是子序列的构成不是简单地逐段分割,而是将相隔某个增量dk的记录组成一个子序列,让增量dk逐趟缩短(如依次取5,3,1),知道dk=1为止。
  希尔排序的优点是让关键值小的元素能很快的前移,并且在序列基本有序时,在使用直接插入排序处理,时间效率会大大提高。希尔排序的时间效率根据经验公式在O(n1.25)~O(1.6n1.25)。空间效率仍为O(1)。但由于记录交换位置后再采用直接插入排序,希尔排序算法并不稳定。

def shell_sort(R):
    num = len(R) - 1
    print R[1:]
    for dk in [5,3,1]:
        if num % dk == 0:
            dk_num = num/dk
        else:
            dk_num = num/dk + 1
        for a in range(dk):
            # 将dk增量记录存储到列表l,直接插入排序后赋值到列表R中,思路清晰但空间复杂度为O(n)
            # 也可不单独存储为l,空间复杂度为O(1)
            l = []
            for i in range(dk_num):
                if (1+a+dk * i) <= num:
                    l.append(R[1+a + dk * i])
            l.insert(0, 0)
            print dk, l
            for i in range(2, len(l)):
                l[0] = l[i]
                if l[i] >= l[i-1]:
                    l[i] = l[0]
                else:
                    for t in range(i):
                        j = i - t
                        if l[j] > l[0]:
                            l[j+1] = l[j]
                        if l[j-1] <= l[0]:
                            l[j] = l[0]
                            break
            for i in range(len(l) - 1):
                R[1+a + i * dk] = l[i + 1]
        print R[1:]
        return R

希尔排序的中间过程:

[13, 6, 3, 31, 9, 27, 5, 11]
第 1 次dk=5:[13, 27, 49, 55, 4, 49, 38, 65, 97, 76]#13 27排序 2 次dk=3:[13, 4, 49, 38, 27, 49, 55, 65, 97, 76]#13 31 5排序3 次dk=1:[4, 13, 27, 38, 49, 49, 55, 65, 76, 97]#5,6,3,13,9,27,31,11排序 
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/haha_point/article/details/78987662
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-07 22:35:57
  • 阅读 ( 806 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢