数据结构——希尔排序
希尔排序是一种插入排序,它对直接插入排序进行优化,使算法复杂度降低达到更低,最好的情况是 n ( l o g 2 n ) 2 n(log_2 n)^2 n(log2n)2 。其优化的思想如下:
普通的直接插入排序是线性的从第一个到最后一个,每次保持一个排好序的数组,再插入一个元素进去,找到自己的位置,插入后不破坏有序性,第一个元素自身就是一个有序的数组。所以初始时是满足的,对第 i i i个待插入的元素可知,有一个由 i − 1 i-1 i−1 个元素组成的有序序列。他依次向前比较找到自己的位置,并且插入后形成一个 i i i 个元素组成的有序序列。对最后一个数字插入后形成一个由 n n n 个数组成的有序序列,那么排序就结束了,并且所有的数字都排好了。这里最耗费时间的步骤就是第 i i i 个数字想要找到自己在 i − 1 i-1 i−1 序列中的位置是要依次往前比较的,最糟糕的情况是要比较 i − 1 i-1 i−1 次的。但是如果待排序列是一个比较有序的数组的话,那么就可以尽量的避免这种情况。这就是希尔排序的思想。
希尔排序为了每一次操作都要使得序列变得更加的“基本有序”,他就将间隔为 k k k 个位置的 n / k n/k n/k 数进行直接插入排序,有k组这样的数,所以是进行了 k k k 次直接插入排序 。再缩小 k k k ,再进行上述操作。直到缩小 k k k 到1,那就是对整个的序列来一次直接插入排序,就成为了有序的了。这样子的时间复杂度在待排序列大的时候有明显的优势。
给出序列:
49 | 38 | 65 | 97 | 76 | 13 | 27 | 49 | 55 | 4 |
---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
先令 k = 5 k=5 k=5
则第一组要排序的是:
49 | 38 | 65 | 97 | 76 | 13 | 27 | 49 | 55 | 4 |
---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 1 | 2 | 3 | 4 | 5 |
下标相同的分为同一组进行直接插入排序,排完之后如下:
13 | 27 | 49 | 55 | 4 | 49 | 38 | 65 | 97 | 76 |
---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
在选择 k = 3 k=3 k=3
第二组要排序的是:
13 | 27 | 49 | 55 | 4 | 49 | 38 | 65 | 97 | 76 |
---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 | 1 |
下标相同的分为同一组进行直接插入排序,排完之后如下:
13 | 4 | 49 | 38 | 37 | 49 | 55 | 65 | 97 | 76 |
---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
最后选择 k = 1 k=1 k=1 对全体一次直接插入排序:
4 | 13 | 37 | 38 | 49 | 49 | 55 | 65 | 76 | 97 |
---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
完成排序。
这个序列的选择是有依据的。一般是由这个函数产生: d l t a [ k ] = 2 t − k + 1 , 0 ≤ k ≤ l o g 2 n − 1 dlta[k] = 2^{t-k} +1 ,0\le{k}\le{log_2{n-1}} dlta[k]=2t−k+1,0≤k≤log2n−1.
…9,5,3,1.
相信能用到的并不多 ,只是作为一个学习而已。
实现代码如下:
操作时选择第0个位置暂时性存放元素。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int a[11] = {0,49,38,65,97,76,13,27,49,55,4};
int dlta[4] = {5,3,2,1};
void shellInsort(int dk) {
int length = 10;
for(int i=dk+1; i<=length; i++) {
if(a[i]<a[i-dk]) {
a[0] = a[i];
int j;
for(j=i-dk; j>0 && a[j]>a[0]; j-=dk) {
a[j+dk] = a[j];
}
a[j+dk] = a[0];
}
}
}
void shellsort() {
for(int i=0; i<4; i++)
shellInsort(dlta[i]);
}
int main() {
shellsort();
for(int i=1; i<=10; i++)
printf("%d ",a[i]);
return 0;
}