排序2 - 希尔排序

希尔排序(shell sort)是改进后的插入排序,不同的是其设置一个步长,将输入按步长分组,对每组元素进行插入排序。然后减少步长,再次分组插入排序。直到步长变为1,也即对所有元素进行插入排序。

说明

一般来说,习惯于将初始步长设置为 n/2, 然后每次减半,直至为1。一个步长对应一趟分组排序。

找到一个特别好的图说明一下,出处为https://www.cnblogs.com/chengxiao/p/6104371.html

实现

鄙人不才,用python实现了一个版本,代码如下:

def shell_sort(A):
    if(len(A)<=1):  # 处理边界情况
        return
    gap = len(A)/2  # 初始化步长

    while(gap>0):
        for i in xrange(0, gap):    # 进行gap次排序
            start = i + gap     

            while(start<len(A)):    # 对一组元素进行插入排序
                flag = A[start]
                insert_index = start
                while(insert_index-gap>=0 and A[insert_index-gap]>flag):
                    A[insert_index] = A[insert_index-gap]
                    insert_index -= gap
                A[insert_index] = flag
                start += gap

        gap /= 2     # 减少步长

问题

初学者可能就有很多疑问:

  • 为什么要分组排序,还要改变步长多次操作,一次搞定不是更好吗?
  • 分组排序方法,为什么要是插入排序,为什么不是快速排序,冒泡排序之类的办法?

回答第一个问题,虽然插入排序的次数变多了,但时间复杂度降低了。正常情况时间复杂度为O(n1~2),即使在现在,数学上也很难证明希尔排序的时间复杂度。有人用大量实验数据作统计,在排序数组足够大的情况下,时间复杂度约为O(n1.3)。直观上可以这么理解,每次分组排序使得组内的数字有序,进而整体的有序性增加。使得下次减少步长再作排序所花费的时间变少。最终这个累加使得整体的时间复杂度降低。

第二个问题,其实这个问题我也没有搞清楚,毕竟希尔排序的时间复杂度尚且无法求解,换句话说还无法给出严谨的数学解释。换个排序办法行不行?肯定行,但时间复杂度至少没有插入排序的好。冒泡排序同选择排序,稳定在O(n2)的时间复杂度,先否定。至于为什么不是其他排序方法,如果有大神看到这个问题,求解释!

复杂度和稳定性

时间复杂度O(n1~2);

未用到额外空间,空间复杂度O(n);

毫无疑问,分组排序的过程中,组内排序使得组之间元素的相对位置发生了改变,为不稳定排序算法。

 

posted @ 2017-12-19 14:44  年华似水丶我如风  阅读(171)  评论(0编辑  收藏  举报