希尔排序也叫递减增量排序,是第一批冲破O(n2)的算法之一,他的算法思想很简单,首先拟定一个增量gap,一般是从len(nums)//3或者len(nums)//2开始,然后对序列nums[i,i+gap,i+gap*k…]进行插入排序,一轮迭代完成后gap=gap//2,知道gap=1时,排序完成。
- 算法步骤是:
- 1:选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;:2:按增量序列个数 k,对序列进行 k 趟排序;
- 2:每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序
- 举个栗子:
- 图片来源:图解排序算法(二)之希尔排序
- 代码如下:
import math
def shellSort(nums):
n = len(nums)
gap = n//2
while gap > 0:
for i in range(gap, n):
temp = nums[i]
j = i - gap
while j >= 0 and nums[j] > temp:
nums[j+gap] = nums[j]
j -= gap
nums[j+gap] = temp
gap = math.floor(gap//2)
nums = [3,38, 5, 44, 15, 36]
shellSort(nums)
print(nums)
- 算法解析:希尔排序是在原数组进行操作,此外只有一个gap的新增常量,因此希尔排序的空间复杂度是O(1)。希尔排序的具体时间复杂度不是很好计算,只能拆成两个循环,分别分析是属于哪种类型的复杂度,首先观察第一层循环,迭代公式是 gap = math.floor(gap//2),很明显这是一个O(log n)的时间复杂度,再观察第二层循环,迭代公式是for i in range(gap, n),很明显是一个O(n)的复杂度,最后观察第三层循环,迭代公式是j -= gap,而gap = math.floor(gap//2)因此可以视为一个O(log n)的复杂度,这也是希尔跑排序最坏的时间复杂度O(nlog2 n)。
- 该算法在进行过程中有可能改变相等元素的相对位置,因此是一种不稳定排序算法。
- 举个例子,如数8 5 5 6 4 gap = 2
- 第一轮: 5 5 4 6 8 ,可见,索引2对应的5在第一轮和索引为0的8交换了位置,两个5的相对位置发生了变化。