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

概要

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

算法思想

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

算法要点

增量取法

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

逆转数

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

稳定性与时间复杂度

排序算法 稳定性 时间复杂度 最好情况 最坏情况 空间复杂度
希尔排序 不稳定 O(n1.5) O(1) 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

添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值