希尔排序shell sort是一种算法,该算法首先对彼此分开的元素进行排序,然后依次减小要排序的元素之间的间隔。它是插入排序的通用版本。
在希尔排序中,将按特定间隔对元素进行排序。元素之间的间隔根据使用的顺序逐渐减小。shell排序的性能取决于给定输入数组使用的序列类型。
使用的一些最佳顺序是:
- Shell的原始顺序:
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
- 希伯德的增幅:
1, 3, 7, 15, 31, 63, 127, 255, 511…
- Papernov和Stasevich增量:
1, 3, 5, 9, 17, 33, 65,...
- 普拉特:
1, 2, 3, 4, 6, 9, 8, 12, 18, 27, 16, 24, 36, 54, 81....
Shell Sort如何工作?
- 假设我们需要对以下数组进行排序。
初始数组
- 我们
(N/2, N/4, ...1
在算法中使用了shell的原始序列作为间隔。
在第一个循环中,如果数组大小为0N = 8
,则对间隔为的元素N/2 = 4
进行比较并交换(如果它们不按顺序排列)。- 将第0个元素与 第四名 元素。
- 如果第0个元素大于 第四名 然后, 第四名首先将元素存储在
temp
变量中,并将0th
元素(即更大的元素)存储在该4th
位置中,将其中存储的元素temp
存储在该0th
位置中。以n / 2间隔重新排列元素
对于所有其余元素,此过程将继续进行。以n / 2间隔重新排列所有元素
- 在第二个循环中,采用的间隔,
N/4 = 8/4 = 2
并再次对位于这些间隔的元素进行排序。以n / 4间隔重新排列元素
此时您可能会感到困惑。比较当前间隔中数组中的所有元素。
的元素 第四名和2nd
位置进行比较。的元素第二名和0th
位置也进行比较。比较当前间隔中数组中的所有元素。 - 其余元素的处理相同。
以n / 4间隔重新排列所有元素
- 最后,当间隔
N/8 = 8/8 =1
为时,对间隔为1的数组元素进行排序。现在,该数组已完全排序。以n / 8间隔重新排列元素
希尔排序算法
希尔排序(数组,大小)
为间隔I < -大小/ 2n的下降到1
对每个间隔“i”的数组
排序所有在间隔元件“i”的
结束希尔排序
Java示例
import java.util.Arrays;
public class ShellSortDemo {
/* An utility function to print array of size n */
/* function to sort array using shellSort */
void sort(int A[]) {
int n = A.length;
// Start with a larger gap, then reduce the gap to 1
// we take gap sequence in order of |N/2|, |N/4|, |N/8|...1
for (int gap = n / 2; gap > 0; gap /= 2) {
// we perform gapped insertion sort for this gap size.
// The first gap elements a[0..gap-1] are already
// in gapped order keep adding one more element
// until the entire array is gap sorted
for (int i = gap; i < n; i += 1) {
// store a[i] in temp and make a hole at
// position i
int temp = A[i];
// shift earlier gap-sorted elements up until
// the correct location for a[i] is found
int j;
for (j = i; j >= gap && A[j - gap] > temp; j -= gap)
A[j] = A[j - gap];
// put temp (the original a[i]) in its correct
// location
A[j] = temp;
}
}
}
// Driver method
public static void main(String args[]) {
int arr[] = { 61, 109, 149, 111, 34, 2, 24, 119, 122, 125, 27, 145 };
// print unsorted array using Arrays.toString()
System.out.print("Unsorted array: ");
System.out.println(Arrays.toString(arr));
ShellSortDemo ob = new ShellSortDemo();
ob.sort(arr);
System.out.print("Sorted array: ");
// print sorted array
System.out.println(Arrays.toString(arr));
}
}
public class ShellSortDemo2 {
public static void main(String[] args) {
// Array of 20 elements
int[] intArr = { 47, 85, 620, 3456, 7, 10, 4500, 106, 345, 1000, 67, 80, 5500, 34, 78, 782, 4, 0, 99, 190 };
int[] sortedArray = shellSort(intArr);
System.out.println("Sorted array is- ");
for (int num : sortedArray) {
System.out.print(num + " ");
}
}
private static int[] shellSort(int[] intArr) {
int gap = 1;
int temp;
// initial gap value calculation
while (gap <= intArr.length / 3) {
gap = (gap * 3) + 1;
}
while (gap > 0) {
for (int i = gap; i < intArr.length; i++) {
temp = intArr[i];
int j;
for (j = i; j > gap - 1 && intArr[j - gap] >= temp; j = j - gap) {
intArr[j] = intArr[j - gap];
}
intArr[j] = temp;
}
// next gap value calculation
gap = (gap - 1) / 3;
}
return intArr;
}
}
复杂
Shell排序是一种不稳定的排序算法,因为该算法不会检查间隔之间的元素。
时间复杂度
- 最坏情况复杂度:小于或等于 shell排序的最坏情况复杂度始终小于或等于。 根据Poonen定理,壳排序的最坏情况复杂度是或或介于两者之间。
O(n2)
O(n2)
Θ(Nlog N)2/(log log N)2)
Θ(Nlog N)2/log log N)Θ(N(log N)2)
- 最佳情况复杂度:
O(n*log n)
对数组进行排序后,每个时间间隔(或增量)的比较总数等于数组的大小。 - 平均案件复杂度:
O(n*log n)
在左右。O(n1.25)
复杂程度取决于选择的间隔。对于选择的不同增量序列,上述复杂度有所不同。最佳递增顺序未知。
空间复杂度:
外壳排序的空间复杂度为O(1)
。
希尔排序应用
在以下情况下使用Shell排序:
- 调用堆栈是开销。uClibc库使用这种排序。
- 递归超出限制。bzip2压缩器使用它。
- 当靠近的元素相距很远时,插入排序的效果不佳。壳排序有助于缩短封闭元素之间的距离。因此,将执行的交换次数将更少。