python 实现 希尔排序

首先来一段专业解释:(来源于百度百科)
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止

简单来说,就是某个规则(就是上文中提到的增量)将待排序数组分为若干个小组,然后针对每一个小组进行插入排序,每排列一次,待排序数组就更“有序”一些。通过逐次减少分组个数,达到最终排序的目的。原理如下图

希尔排序图解

要实现该算法,首先解决以下问题

  1. 增量怎么选取(就是分组的个数,逐次递减)
  2. 分好的小组数据插入到大数组中怎么保证“一个萝卜一个坑对应”(这样说可能不是特别合适,可以理解为抽出来一组数据后,待排序数组存在很多空缺,在给抽出的小组排序后,依次补全待排序大数组的空缺)
    还是话不多说,直接上代码:
#!/usr/bin/env python
# -*-coding:utf-8-*-
# @Time:2021/7/12 19:04
# @Author:ZhangFY
# @File:hill_sort.py

import random
import time

'''
    此文件为希尔排序的python实现
    希尔排序算法核心,是由简单的插入排序进阶改进,又称缩小增量排序,核心操作为首先将待排序队列
    依据某种增量值进行分组,每个分组都进行插入排序,直到增量值为1时,最后执行一遍插入排序完成排序
    希尔排序执行效率远高于普通插入排序
'''

def timer_count(f):
    def decor(*args,**kwargs):
        s_time = time.time()
        r = f(*args,**kwargs)
        e_time = time.time()
        print("{}函数耗时{}秒".format(f.__name__,e_time-s_time))
        return r
    return decor

# 插入排序功能函数,插入排序核心为:单个元素可认为是有序的
@timer_count
def insert_sort(l):
    print("排序前:",l)
    for i in range(1,len(l)):
        j = i
        temp = l[i]
        while j > 0 and l[j-1] > temp:    # 寻找插入位置
            l[j] = l[j-1]
            j -= 1
        l[j] = temp
    print("排序后:",l)

def insert_sort_inside(l):
    for i in range(1,len(l)):
        j = i
        temp = l[i]
        while j > 0 and l[j-1] > temp:    # 寻找插入位置
            l[j] = l[j-1]
            j -= 1
        l[j] = temp

# 这里定义增量为len(l)/2,len(l)/2/2,len(l)/2/2/2.....1
# 希尔排序主要逻辑
@timer_count
def hill_way(l):
    if isinstance(l,list):
        print("排序前",l)
        increment = len(l) // 2
        while increment > 0:
            # 获取当此循环分组个数,分组个数决定下方
            for index in range(increment):
                group_l = []
                index_l = []
                group_num = len(l) // increment  # 获取当前分组个数下每个组中元素个数

                for ti in range(group_num):
                    group_l.append(l[index + ti * increment])     # 根据组数,每个组元素个数,构建分组后的列表
                    index_l.append(index + ti * increment)        # 分组后列表对应原数据的索引,便于排序后逐个替换到原数据中

                insert_sort_inside(group_l)                       # 分组后数据排序
                i = 0
                for index_info in index_l:
                    l[index_info] = group_l[i]                    # 分组后数据替换
                    i += 1
            increment = increment // 2
            if increment == 1:
                insert_sort_inside(l)                             # 最后一轮
                break
        print("排序后",l)
    else:
        raise TypeError("函数hill_way参数类型有误")

if __name__ == '__main__':
    l = [random.randint(5,500) for x in range(250000)]
    import copy
    ll = copy.deepcopy(l)
    # 测试两块执行时间对比
    hill_way(l)
    insert_sort(ll)

在实现该算法的时候,我在处理每个小组排序后向原数组中插入的步骤时感觉稍微麻烦,有点违背了python 的 优雅,简洁的特点,等空了再进行完善吧。

初次编写博客,语言组织、表达能力等等感觉差了好多,对于文中出现的问题,欢迎大家留言指正。个人github

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值