插入排序基本思想 : 每一步将一个待排序的元素,按其排序码的大小,插入到前面已经排好序的一组元素的合适位置上去,直到元素全部插完为止。
【直接插入排序】:当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序 进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移
如上图所示各趟排序后的结果 :
- 元素集合越接近有序, 直接插入排序算法的时间复杂度越高
- 最优的情况下 : 时间复杂度为 O(n)
- 最差的情况下 : 时间复杂度为 O(n^2)
- 空间复杂度 : O(1) , 它是一种稳定的排序算法
【希尔排序】: 又称缩小增量排序,是对直接插入排序的优化 , 如下图所示 , 以3为间隔 , 每次进行排序 , 使数组接近于有序 ,
这样就能减少元素后移的次数 , 这样在大量数据排序时 , 效率会大大提高 ; 在下面的测试中会有明显的差别
代码如下 :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
//直接插如排序
void InsertSort(int *a, int len)
{
assert(a);
//由于end是从i+1开始进行排序的n,所以i要小于len-1
for (int i = 0; i < len - 1; i++){
int end = i+1;
//使用临时变量记录end下标的值
int tmp = a[end];
//如果end下标的值小于i当前下标的值,则进行元素后移
if (a[end] < a[i]){
//由于是在已经排序好的数组插入元素,所以后移的结束条件为
//当end走到数组最开始的位置和临时变量不小于end-1代表的元素时
while (end > 0 && tmp < a[end - 1]){
a[end] = a[end-1];
end--;
}
}
//将临时变量放到end所走到的位置
a[end] = tmp;
}
}
//希尔排序(缩小增量排序)
void ShellSort(int *a, int len)
{
assert(a);
int idx = len;
while (idx > 1)
{
//idx为每次插入排序所需要的间隔
idx = idx / 3 + 1;
for (int i = 0; i < len - idx; i++){
int end = i + idx;
int tmp = a[end];
if (a[end] < a[i]){
//注意:这里的判断条件和直接插入不同,由于希尔排序是跳跃式的插入排序
//所以这里end的结束不是数组的最开始,而是i
while (end > i && tmp < a[end - idx]){
a[end] = a[end - idx];
end -= idx;
}
}
a[end] = tmp;
}
}
}
void Printf(int *a, int len)
{
assert(a);
for (int i = 0; i < len; i++)
printf("%d ", a[i]);
printf("\n");
}
int main()
{
int a[100000] = { 0 };
int b[100000] = { 0 };
srand(time(0));
for (int i = 0; i < 100000; i++){
b[i] = a[i] = rand();
}
int begin1 = clock();
InsertSort(a, sizeof(a)/sizeof(int));
int end1 = clock();
int begin2 = clock();
ShellSort(b, sizeof(b) / sizeof(int));
int end2 = clock();
//比较直接插入排序和希尔排序的效率
printf("直接插入排序所需要的时间 : %d ms\n", end1 - begin1);
printf("希尔排序所需要的时间 : %d ms\n", end2 - begin2);
system("pause");
return 0;
}
在上面的代码中随机生成了100000个数据用直接插入排序和希尔排序分别进行测试 , 调试结果如下 :
若有出错或不懂的地方, 欢迎留言, 共同进步 !