在本教程中,您将学习希尔排序的工作方式。此外,您还将找到使用C语言的示例。
希尔排序是一种算法,该算法首先对彼此分开的元素进行排序,然后依次缩短要排序的元素之间的间隔。它是插入排序的一个通用版本。
在希尔排序中,按特定间隔对元素进行排序。元素之间的间隔根据使用的顺序逐渐减小。希尔排序的性能取决于给定输入数组使用的序列类型。
使用的一些最佳序列是:
- 希尔原始序列:N/2 , N/4 , …, 1
- Knuth增量:1, 4, 13, …, (3k – 1) / 2
- Sedgewick增量:1, 8, 23, 77, 281, 1073, 4193, 16577…4j+1+ 3·2j+ 1
- Hibbard增量:1, 3, 7, 15, 31, 63, 127, 255, 511…
- Papernov和Stasevich增量:1, 3, 5, 9, 17, 33, 65,…
- Pratt:1, 2, 3, 4, 6, 9, 8, 12, 18, 27, 16, 24, 36, 54, 81…
希尔排序如何工作?
- 假设我们需要对以下数组进行排序。
- 在算法中,我们使用希尔的原始序列(N/2,N/4,…1)作为间隔。
在第一个循环中,如果数组大小为 N = 8,则对间隔为N/2 = 4的元素进行比较并交换(如果它们不按顺序排列)。
a. 将第0个元素与第4个元素进行比较。
b. 如果第0个元素大于第4个元素,则第4个元素首先存储在temp变量中,第0个元素(即较大的元素)存储在第4个位置,而temp中存储的元素存储在第0个位置。
对于所有剩余的元素,此过程将继续进行。
- 在第二个循环中,取N/4=8/4=2的间隔,并再次对位于这些间隔处的元素进行排序。
在这一点上你可能会感到困惑。
第4位和第2位的元素被比较,第2位和第0位的元素也进行了比较。数组中当前间隔的所有元素都被比较。 - 对剩余元素也进行相同的处理。
- 最后,当间隔为N/8=8/8=1时,对间隔为1的数组元素进行排序。数组现在已完成排序。
注:
原文第二次排序的图例有误。
第一次间隔为4,排序之后数组为:
5 6 3 1 9 8 4 7
正确。
第二次间隔为2,分别将5,3,9,4和3,4,5,9排序,排序之后的数组为:
3 1 4 6 5 7 9 8
第三次间隔为1,排序之后的数组为:
1 3 4 5 6 7 8 9
希尔排序算法伪代码
shellSort(array, size)
for interval i <- size/2n down to 1
for each interval "i" in array
sort all the elements at interval "i"
end shellSort
C示例
// Shell Sort in C programming
#include <stdio.h>
// Shell sort
void shellSort(int array[], int n) {
// Rearrange elements at each n/2, n/4, n/8, ... intervals
for (int interval = n / 2; interval > 0; interval /= 2) {
for (int i = interval; i < n; i += 1) {
int temp = array[i];
int j;
for (j = i; j >= interval && array[j - interval] > temp; j -= interval) {
array[j] = array[j - interval];
}
array[j] = temp;
}
}
}
// Print an array
void printArray(int array[], int size) {
for (int i = 0; i < size; ++i) {
printf("%d ", array[i]);
}
printf("\n");
}
// Driver code
int main() {
int data[] = {
9, 8, 3, 7, 5, 6, 4, 1};
int size = sizeof(data) / sizeof(data[0]);
shellSort(data, size);
printf("Sorted array: \n");
printArray(data, size);
}
复杂度
希尔排序是一种不稳定的排序算法,因为该算法不检查间隔之间的元素。
时间复杂度
- 最坏情况复杂度:小于或等于O( n 2 n^2 n2)
根据Poonen定理,希尔排序的最坏情况复杂度为 Θ ( N l o g N ) 2 / ( l o g l o g N ) 2 ) Θ(Nlog N)^2/(log log N)^2) Θ(NlogN)2/(loglogN)2) 或 Θ ( N l o g N ) 2 / l o g l o g N ) Θ(Nlog N)^2/log log N) Θ(NlogN)2/loglogN) 或 Θ ( N ( l o g N ) 2 ) Θ(N(log N)^2) Θ(N(logN)2) 或介于两者之间。 - 最佳情况复杂度:O(n*log n)
当数组已经排序时,每个间隔(或增量)的比较总数等于数组的大小。 - 平均情况复杂度:O(n*log n)
大约是 O ( n 1.25 ) O(n^{1.25}) O(n1.25)
复杂度取决于所选的间隔。对于选择的不同增量序列,上述复杂度不同。最佳的增量序列未知。
空间复杂度:
希尔排序的空间复杂度为O(1)。
希尔排序的应用
在以下情况下使用希尔排序:
- 调用堆栈是日常开销。uClibc库使用这种排序。
- 递归超出限制。bzip2压缩器使用它。
- 当相邻元素相距较远时,插入排序的性能不好。希尔排序有助于缩短相邻元素之间的距离。因此,要执行的交换的数量将更少。
参考文档
[1]Parewa Labs Pvt. Ltd.Shell Sort Algorithm[EB/OL].https://www.programiz.com/dsa/shell-sort,2020-01-01.
[2]Baidu.希尔排序[EB/OL].https://baike.baidu.com/item/希尔排序,2020-11-18.