【校招VIP】排序算法之希尔排序

05月13日 收藏 0 评论 1 java开发

【校招VIP】排序算法之希尔排序

转载声明:文章来源https://blog.csdn.net/u022812849/article/details/107142652

希尔排序

1959年由唐纳德·希尔(Donald Shell)提出希尔排序。

希尔排序的思想:把数组中的元素看作是一个矩阵,分成m列,逐列进行排序(一般采用插入排序),m从某个整数逐渐减为1,当m为1时,整个序列将完全有序。因此,希尔排序也被称为递减增量排序(Diminishing Increment Sort)。

矩阵的列数取决于步长序列(step sequence),比如,如果步长序列为{1,5,19,41,109,…},就代表依次分成109列、41列、19列、5列、1列进行排序。不同的步长序列,执行效率也不同。

实例

希尔本人给出的步长序列是n/2^k(其中n为数组长度),例如要对下面的数组进行排序,n为16,步长序列是{1, 2, 4, 8}:

首先分成8列进行排序:

然后再分成4列进行排序:

再分成2列进行排序:

最后分成一列进行排序:

最后数组中的元素就变成有序的了。

疑惑:直接分成一列进行排序不就行了,为什么要分成这么多列?不难看出来,从8列变为1列的过程中,逆序对的数量在逐渐减少,而希尔排序底层会使用插入排序,插入排序的时间复杂度与逆序对的数量成正比,这样就可以提高插入排序的效率。

因此希尔排序底层一般使用插入排序对每一列进行排序,也很多资料认为希尔排序是插入排序的改进版。

代码实现

protected void sort() {

List<Integer> stepSequence = shellStepSequence();

for (Integer step : stepSequence) {
sort(step);
}

}

private void sort(Integer step) {

// 对每一列进行插入排序
for (int col = 0; col < step; col++) {

// 插入排序
for (int begin = col + step; begin < array.length; begin += step) {
int cur = begin;
E v = array[cur];
while (cur > col && cmp(v, array[cur - step]) < 0) {
array[cur] = array[cur - step];
cur -= step;
}
array[cur] = v;
}
}
}

private List<Integer> shellStepSequence() {

// n/2^k
int n = array.length;
List<Integer> list = new ArrayList<>();

while ((n >>= 1) > 0) {
list.add(n);
}

return list;
}

复杂度与稳定性

最好情况是步长序列只有1,且序列几乎有序,时间复杂度为O(n)。

希尔本人给出的步长序列,最坏情况时间复杂度是 O(n^2)。

希尔排序的时间复杂度与步长序列有关。

C 1条回复 评论
带脑斧

不过还有待完善,挺好的,不错的资源。

发表于 2022-08-08 23:00:00
0 0