希尔排序

希尔排序是对插入排序的优化。
        插入排序在数据集”基本有序“时,效率最高,因此,希尔排序的优化思路便是先把数据集变成”基本有序“,  再进行插入排序。
        那么如何变成”基本有序“?
        1、对列表按一定的间隔(gap)进行分组,公式:gap  =  length  /  2
        如  list_datas  =  [88,  6,  57,  72,  60,  42,  83,  73,  48,  85]
        因为  gap  =  5,
                那么  88,42为一组,
                        6,83为一组,
                        57,73为一组,
                        72,48为一组,
                        60,  85为一组
                注意这里只是”逻辑分组“,并没有改变它们在列表中的位置
        2、分别对每个分组进行排序调整,调整完毕后,gap  //=  2,  然后再重复进行  1  操作,
              当  gap  =  1  时,便实现整个列表”基本有序“,此时再进行插入排序,完成整个希尔排序

时间复杂度:

思路一:
        1、对每个分组进行排序,因为每个分组都只有两个数,因此,直接进行判断,然后调换顺序
        2、gap  //  =  2,  重复1操作直至  gap  ==  1,  此时对整个列表进行插入排序

def shell_sort1(datas):
    length = len(datas)
    gap = length // 2
    while gap > 1:
        for index in range(0, length - gap):
            if datas[index] > datas[index + gap]:
                temp = datas[index]
                datas[index] = datas[index + gap]
                datas[index + gap] = temp
        gap //= 2

    for index in range(0, length):
        pre_index = index - 1
        current = datas[index]
        while pre_index >= 0 and datas[pre_index] > current:
            datas[pre_index + 1] = datas[pre_index]
            pre_index -= 1
        datas[pre_index + 1] = current
    return datas

思路二:
        对每个分组进行排序时,可以直接使用插入排序。
        问题:每个分组的数字,都不相邻,如何进行类似  pre_index  +  1  的操作?
        答:  把  pre_index  +  1  改成  pre_index  +  gap  就行了  (又是一个数学思维)

        这样,给分组进行排序  和  最终整个列表的排序  都可以使用插入排序,代码可以复用,空间复杂度就降低了

def shell_sort2(datas):
    length = len(datas)
    gap = length // 2
    while gap >= 1:
        for end_index in range(0, length - gap, gap):
            pre_index = end_index
            current = datas[end_index + gap]
            while pre_index >= 0 and datas[pre_index] > current:
                datas[pre_index + gap] = datas[pre_index]
                pre_index -= gap
            datas[pre_index + gap] = current
        gap //= 2
    return datas