壳排序是一种算法,该算法首先对彼此远离的元素进行排序,然后依次减小要排序的元素之间的间隔。它是插入排序的通用版本。
在外壳排序中,将按特定间隔对元素进行排序。元素之间的间隔根据使用的顺序逐渐减小。 shell排序的性能取决于给定输入数组使用的序列类型。
使用的一些最佳顺序是:
- Shell的原始序列:
N/2 , N/4 , …, 1
- Knuth的增量:1,4,13
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
1, 3, 7, 15, 31, 63, 127, 255, 511…
- Papernov和Stasevich增量:1、3、5、9、17、33、65
1, 3, 5, 9, 17, 33, 65,...
- 普拉特(Pratt):
1, 2, 3, 4, 6, 9, 8, 12, 18, 27, 16, 24, 36, 54, 81....
Shell Sort如何工作?
- 假设我们需要对以下数组进行排序。
- 我们在算法中使用了外壳的原始序列
(N/2, N/4, ...1
)作为间隔。在第一个循环中,如果数组大小为
N = 8
,则对间隔为N/2 = 4
的元素进行比较并交换(如果顺序不正确)。- 将第0个元素与第4个元素进行比较。
- 如果第0个元素大于第 4个元素,则第4个元素首先存储在
temp
变量中,第0th
元素(即,更大的元素)存储在第4th
位置,而存储在temp
的元素存储在0th
位置。
对于所有其余元素,此过程将继续进行。
- 在第二个循环中,采用
N/4 = 8/4 = 2
的间隔,并再次对位于这些间隔的元素进行排序。
此时您可能会感到困惑。
比较第4位和
2nd
位的元素。还比较了0th
2位和0th
位的元素。比较当前间隔中数组中的所有元素。 - 其余元素的处理相同。
- 最后,当间隔为
N/8 = 8/8 =1
时,将对间隔为N/8 = 8/8 =1
的数组元素进行排序。现在,该数组已完全排序。
壳排序算法
shellSort(array, size)
for interval i
Python,Java和C / C++示例
Python
爪哇
C
C++
# Shell sort in python
def shellSort(array, n):
# Rearrange elements at each n/2, n/4, n/8, ... intervals
interval = n // 2
while interval > 0:
for i in range(interval, n):
temp = array[i]
j = i
while j >= interval and array[j - interval] > temp:
array[j] = array[j - interval]
j -= interval
array[j] = temp
interval //= 2
data = [9, 8, 3, 7, 5, 6, 4, 1]
size = len(data)
shellSort(data, size)
print('Sorted Array in Ascending Order:')
print(data)
// Shell sort in Java programming
import java.util.Arrays;
// Shell sort
class ShellSort {
// Rearrange elements at each n/2, n/4, n/8, ... intervals
void shellSort(int array[], int n) {
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;
}
}
}
// Driver code
public static void main(String args[]) {
int[] data = { 9, 8, 3, 7, 5, 6, 4, 1 };
int size = data.length;
ShellSort ss = new ShellSort();
ss.shellSort(data, size);
System.out.println("Sorted Array in Ascending Order: ");
System.out.println(Arrays.toString(data));
}
}
// Shell Sort in C programming
#include
// 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);
}
// Shell Sort in C++ programming
#include
using namespace std;
// 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) {
int i;
for (i = 0; i < size; i++)
cout << array[i] << " ";
cout << endl;
}
// Driver code
int main() {
int data[] = {9, 8, 3, 7, 5, 6, 4, 1};
int size = sizeof(data) / sizeof(data[0]);
shellSort(data, size);
cout << "Sorted array: \n";
printArray(data, size);
}
复杂
Shell排序是一种不稳定的排序算法,因为该算法不会检查间隔之间的元素。
时间复杂度
- 最坏情况下的复杂度 :小于或等于
O(n 2 )
外壳排序的最坏情况复杂度始终小于或等于O(n 2 )
。根据Poonen定理,壳排序的最坏情况复杂度为
Θ(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(n 1.25 )
。
复杂程度取决于选择的时间间隔。对于选择的不同增量序列,上述复杂度有所不同。最佳递增顺序未知。
空间复杂度:
外壳排序的空间复杂度为O(1)
。
壳牌分类应用
在以下情况下使用Shell排序:
- 调用堆栈是开销。 uClibc库使用这种排序。
- 递归超出限制。 bzip2压缩器使用它。
- 当接近的元素相距很远时,插入排序的效果不佳。壳排序有助于缩短封闭元素之间的距离。因此,将执行的交换次数将更少。