希尔排序是经过分组的插入排序,那么怎么理解呢?在此之前我们先来再次认识一下插入排序。
我们可以看到对于插入排序,前面的元素都是有序的,后面有新的元素插入进来时我们只需要找到对应的位置插入进来即可。
void insert_sort(int * data, int length)
{
int i, j, temp;
for(i = 1; i < length; i++)
{
temp = data[i];
for(j = i - 1; temp < data[j]; j--)
{
data[j + 1] = data[j];
}
data[j + 1] = temp;
}
}
代码的实现就是这样的,这里的temp就相当于当前要插入的元素,然后就是要找到对应的位置插入进去,这里可以看到插入时每次移动的步长是1。
直接插入排序的问题就在此:如果在后面来了一个特别小的元素,需要全部移动,那么排序的效率特别低.
例如我们后面插入一个元素2进来,需要把前面所有的元素都往后移动。
这个时候就需要用到希尔排序了,可以把它理解为分组插入排序。
它首先把这8个元素分成2组,每组步长为4进行插入,然后依次让步长除2进行插入,直到步长为1时就是直接插入排序
void shell_sort(int *data, int length)
{
int gap, i, j, temp, k;
for(gap = length / 2; gap > 0; gap /= 2)
{
for(i = gap; i < length; i++)
{
temp = data[i];
for(j = i - gap; j >= 0 && data[j] > temp; j -= gap)
{
data[j + gap] = data[j];
}
data[j + gap] = temp;
}
/*for(k = 0; k < length; k++)
{
printf("%d ", data[k]);
}
printf("\n");*/
}
}
这段代码可能看上去比较晦涩,但它相较于插入排序只是多了分组插入,插入排序时相当于gap的值为1,和插入排序一样需要temp来存储当前插入分组的元素,如果理解起来有困难可以先参考图把每次分组后的值列出来,然后再结合代码把我注释的内容放开去看它不同步长下的值。
和直接插入排序不同,由于希尔排序存在分组插入,所以希尔排序是不稳定的,他们的空间复杂度都是O(1),都属于内排序(空间复杂度小,在内存中)
时间复杂度的平均值希尔排序要优于插入排序,其它的和插入排序是一样的,关于时间复杂度计算的问题大家可以去百度,关于这两种排序的其他问题可以给我留言探讨,感谢!