数据结构之内部排序--希尔排序

概要

-IDE:Pycharm
-Python版本:python3.x
-算法分类:内部排序->插入类排序->希尔排序

算法思想

希尔排序又称缩小增量排序法,是一种基于插入思想的排序方法。它利用了直接插入排序的最佳性质,首先,将待排序的关键字序列分成若干个较小的序列,对子序列进行直接的插入排序,使整个待排序列排好序。
过程如下:
1.首先选定记录间的距离$d_i(i=1)$,在整个待排序记录序列中将所有间隔为$d_1$的记录分成一组,进行组内直接插入排序。
2.然后选取$i=i+1$,记录间的距离为$d_i(d_i<d_i-_1)$,在整个待排序记录序列中,将所有间隔为$d_i$的记录分成一组,进行组内直接插入排序。
3.重复步骤2直至记录间的距离$d_i=1$,此时整个只有一个子序列,对该序列进行直接插入排序,完成整个排序过程。

算法要点

增量取法

关于增量$d$的取法,最初希尔提出取$d=[n/2]$,再取$d=[d/2]$,直到$d=1$为止。该思路的缺点是,奇数位置的元素在最后一步才会与偶数位元素进行比较,使得排序效率低。后来Knuth提出$d=[d/3]+1$。此外还有多种取法,但无法证明那种最优。

逆转数

为了分析希尔排序的优越性,这里引入逆转数的概念。对于待排序列中的某个记录的关键字,它的逆转数是指在它之前比此关键字大的关键字个数。
假设:被调换位置的两个关键字之间有$l$个介于两个关键字之间的数。逆转数之和一定会减小$2l+1$
当逆转数为$0$时则表明整个排序完成。

稳定性与时间复杂度

排序算法 稳定性 时间复杂度 最好情况 最坏情况 空间复杂度
希尔排序 不稳定 $O(n^{1.5})$ $O(1)$

Python代码清单

# !/usr/bin/python3
# _*_  coding:utf-8  _*_
# 希尔排序
 
import random, time, sys
 
 
def SS(number,maxNumber):
    # 生成随机数
    timeStart = time.time()
    listA = [0]  # 0位 一般都空出来,防止out of index 或者做监视哨或者备份某个值。
    for i in range(number):
        listA.append(random.randint(0, maxNumber))  # 添加生成的值。
 
    timeEnd = time.time()
    timeIs = timeEnd - timeStart
    listD = [0, int(number/2)]  # listD用于存放增量d,第0位用0占位,我们从第一位开始循环。
    while True:
        if listD[-1] != 1:  # 判断最后一个元素(增量)是否是1,若不是继续计算增量。
            listD.append(int(listD[-1]/3)+1)  # 计算增量
        else:
            break  # 若是1,则退出循环。
 
    print('生成%d个数的时间是%f' % (number, timeIs))
    # print(listA[1:])  # 从第一位开始输出。0位不显示。
    # print(listD[1:])  # 输出d的增量的列表
    ####################################################
    # 希尔排序算法。  我认为 右边是前,左边是后。
    timeStart = time.time()  # 开始记录时间
    #  算法开始
    for d in listD[1:]:  # 设置循环的次数,与d有关系。
        base = 1 + d  # 从前向后找,从哦能通过d+1位开始。
        for item in range(base, len(listA)):  # 每次增加一位
            if listA[item] < listA[item-d]:  # 如果遇到前面小,后面大的数,
                listA[0] = listA[item]  # 复制前面的数
                aim = item-d  # 选定目标的位置。
                while True:  # 开始循环查询序列。
                    if aim > 0 and listA[0] < listA[aim]:  # 这里应设置条件,以防无限循环。
                        listA[aim + d] = listA[aim]  # 将选定目标位的数后移。
                        aim = aim - d   # 每次向前查找,步长为d
                    else:
                        break  # 条件不符合 break 出
                listA[aim+d] = listA[0]  # 把目标值放入目标位。加d是因为在循环时多减了d。
    #  算法结束
    timeEnd = time.time()  # 记录结束时间。
    timeIs = timeEnd - timeStart  # 排序花费的时间
    print('排序%d个数,花费的时间是%f' % (number, timeIs))
    # print(listA[1:])  # 打印最后排序的列表。
 
 
if __name__ == '__main__':
 
    helpInfo = '''
           This program is for Shell's Sort.
           How to use it! Follow the example!
 
           python Shell's_Sort.py 10 100
 
           The 10 representative will generate ten numbers.
           100 representative the max-number you make.
 
       '''
 
    command = sys.argv[0:]  # 获取从键盘输入的值。
    if len(command) != 3 or 'help' in command:  # 判断是否合法,或包含help
        print(helpInfo)  # 打印帮助文本。
    else:
        try:  # 尝试将输入转化为整数。
            number = int(command[1])
            maxNumber = int(command[2])
        except ValueError:  # 数值型错误。
            print(helpInfo)  # 打印帮助。
            sys.exit(1)  # 退出程序。
        SS(number, maxNumber)  # 一切完好,调用函数。

有什么问题请联系我

QQ:3116316431 (请附上信息)
E-mail:wongyinlong@yeah.net

原文地址:https://www.cnblogs.com/Leon-The-Professional/p/9950090.html