希尔排序
一、什么是希尔排序;
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
二、希尔排序的思想;
希尔排序是插入排序的提升(如果没了解过插入排序建议先去看看插入排序)。他是通过将数据根据每一次的步长不断地分块,并且进行处理,使得数值序列整体上变得不会太过杂乱。使得在利用插入排序的过程中减少交换的次数,从而进行优化。
三、步长(增量)
希尔当年提出n/(2^k),k取1,2,3,4……(n代表数据个数),从而计算出步长。
例如:{9, 5, 2, 7, 8, 1, 3, 5, 4, 8, 7, 6, 2, 1, 5}
根据希尔的公式可以计算出:
(以下除法运算接按照C语言整数除法运算法则)
第一次所需步长是:15 / 2 = 7;
第二次所需步长是:7 / 2 = 3;
第三次所需步长是:3 / 2 = 1;
当步长为一时,所进行的排序和插入排序完全相同,只不过此时的数据在经过前面几次的排序后数值序列已经被进行优化。所以会加快数据的排序。
四、复杂度分析
- 时间复杂度O(n^(1.3~2));
- 空间复杂度O(1);
- 稳定性·:非稳定;
五、图解过程
第一次步长为4,所以将每个数据与之相隔第四个数据进行比较;结果如第二行所示。第二次步长为二,所以在第一排好的序列下再以以二为步长进行排序。直到步长为一时完成排序。
六、代码实现
#include <stdio.h>
#define N 9
//打印
void prin_arr(int *arr);
//排序过程
void shell_sort(int *arr, int n);
void shell_sort(int *arr, int n) {
int step; //步长;
int key; //保护每一组数据排序时的第二个数据;
int i;
int j;
//该排序过程是多组数据同时进行,并不是一组一组的进行;
for (step = N / 2; step > 0; step /= 2) {
for (i = step; i < N; i++) {
key = arr[i]; //保护数据
for (j = i - step; j >= 0 && arr[j] > key; j -= step) {
arr[j + step] = arr[j];
}
arr[j + step] = key; //将保护的数据放到合适的位置;
}
}
}
void print_arr(int *arr) {
int i;
for (i = 0; i < N; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr[] = {9, 5, 2, 7, 6, 5, 4, 9, 8};
print_arr(arr);
shell_sort(arr, N);
print_arr(arr);
return 0;
}