首先来一段专业解释:(来源于百度百科)
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止
简单来说,就是某个规则(就是上文中提到的增量)将待排序数组分为若干个小组,然后针对每一个小组进行插入排序,每排列一次,待排序数组就更“有序”一些。通过逐次减少分组个数,达到最终排序的目的。原理如下图
要实现该算法,首先解决以下问题
- 增量怎么选取(就是分组的个数,逐次递减)
- 分好的小组数据插入到大数组中怎么保证“一个萝卜一个坑对应”(这样说可能不是特别合适,可以理解为抽出来一组数据后,待排序数组存在很多空缺,在给抽出的小组排序后,依次补全待排序大数组的空缺)
还是话不多说,直接上代码:
#!/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