希尔排序(Shell's Sort)
是插入排序的一种又称"缩小增量排序"(Diminishing Increment Sort)
,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。
实现思路:
首先把较大的数据集合分割成若干个小组(逻辑上分组,以下标来分组),然后对每一个小组分别进行插入排序,此时,插入排序所作用的数据量比较小(每一个小组),插入的效率比较高
从上图可以看出,是以下标的相隔距离作为增量来进行分组,我们选取的这个距离称作为增量。在每个分组进行插入排序后,各个分组就变成了有序的了
显然,经过一轮排序后,整个数组变得部分有序
接下来,我们将增量缩小,可以缩小为原增量的一半,继续分组,由于增量缩小,所以每个分组的元素会变多,但由于数组已经部分有序,所以在对每个分组进行插入排序时同样是比较高效的。
对每个分组进行插入排序后
最后继续将增量设置为上一个增量的一半,此时整个数组被分为一组,但有序程度已经很大改进,因此插入排序仍然可以较高效的进行。
最后再对这组数组进行插入排序后,俨然数组已经是有序的了。
代码实现:
def shellSort(arr):
length = len(arr)
gap = length // 2
while gap > 0:
for i in range(gap,length):
j, cur = i, arr[i]
while (j - gap >= 0) and (cur < arr[j - gap]):
arr[j] = arr[j - gap]
j -= gap
arr[j] = cur
gap = gap // 2
if __name__ == "__main__":
arr = [5,7,8,3,1,2,4,6]
print('排序前:',arr)
shellSort(arr)
print('排序后:',arr)
排序前: [5, 7, 8, 3, 1, 2, 4, 6]
排序后: [1, 2, 3, 4, 5, 6, 7, 8]
复杂度:
时间复杂度:
希尔排序的时间复杂度的计算比较复杂,它的复杂度与增量序列有关,即我们每次选择的增量所组成的序列,如果序列是这样的{1,2,4,8,....}
,实际上这种增量序列并不是很好,使用这种增量序列的时间复杂度最坏情况为
O
(
n
2
)
O(n^2)
O(n2),而如果增量序列为
{
1
,
3
,
7
,
.
.
.
,
2
k
−
1
}
\{1,3,7,...,2^{k-1}\}
{1,3,7,...,2k−1},这种序列的时间复杂度最坏情况为
O
(
n
1.5
)
O(n^{1.5})
O(n1.5)。目前较为好的时间复杂度为
O
(
n
1.3
)
O(n^{1.3})
O(n1.3),其增量序列为{1,5,19,41,109,....}
。总之,希尔排序的时间复杂度一般介于
O
(
n
l
o
g
n
)
O(nlog_n)
O(nlogn)到
O
(
n
2
)
O(n^2)
O(n2)之间。
空间复杂度:
O
(
1
)
O(1)
O(1),in-place
对数组进行排序。