一.直接插入排序
单独总结我的另一篇博客:
https://blog.youkuaiyun.com/hansionz/article/details/80835834
- 代码实现
//直接插入排序
int InsertSort(int *num,int len)
{
assert(num);
int i = 0;
//第一个元素已经为有序序列,所以要进行len-1次排序
for (; i < len - 1; i++)
{
int end = i;
int tmp = num[i + 1];//保存非有序区间第一个元素,否则在后边的移动中会改变
//比较后移
while (end >= 0 && num[end]>tmp)
{
num[end+1] = num[end];
--end;
}
//插入到适当位置
num[end + 1] = tmp;
}
}
- 时间复杂度:最优情况,待排序序列接近有序,要移动的关键字只有常数次,它的时间复杂度为
O(N)
;最坏情况,待排序列基本无序,时间复杂度为O(N*N)
。 - 空间复杂度:只开辟了tmp一个空间,所有空间复杂度为
O(1)
。
二.希尔排序
1.什么是希尔排序?
希尔排序又叫缩小增量排序
,它实质上是一种插入排序。一方面,它的发现者DL.Shell
是基于在我们进行直接插入排序的过程中有的记录
移动的太慢了而且移动的次数很大,那能不能想办法让它移动的快一点呢?于是DL.Shell
想到让记录
按下标的一定增量分组,对每组使用直接插入排序算法排序,最后在进行一次直接插入排序。另一方面,希尔排序是对直接插入排序的优化,它先进行预排序,使得待排序列基本有序,在进行直接插入排序O(N)
,所以它主要分为两步
:
- 预排序(预排序之后使得要排序序列接近于有序)
它让记录中大的数字较快的移动到后边,主要是基于这样的想法,让整个记录序列基本有序。
注:图片借用Prepare_y
博主博客中的图片 - 直接插入排序:最后一次排序
gap
必须等于1,基本有序的记录序列进行一次直接排序得到最终排序结果
2.代码实现
//希尔排序(缩小增量排序)
/*最好步长序列是由Sedgewick提出的(1, 5, 19, 41, 109,...)*/
int ShellSort(int *num, int len)
{
assert(num);
int gap = 5;//步长
//最后一次步长必须为1
while (gap >= 0)
{
//1.gap>1时预排序
for (int i = 0; i < len - gap; i++)
{
int end = i;
int tmp = num[end + gap];
while (end >= 0 && num[end] > tmp)
{
num[end + gap] = num[end];
end -= gap;
}
num[end + gap] = tmp;
}
gap -= 2;
}
//2.gap为1时直接插入排序(这时要排序序列已经接近有序)
}
3.效率分析
希尔排序是基于多次预排序让记录中大的数字较快的移动到后边,使得记录序列基本有序,而不是像直接排序中一个一个往后移动。总的来说希尔排序的效率肯定比直接插入排序要高。因为希尔排序的时间复杂度和它的步长选择有关系,它的平均时间复杂度为n*log(n)
。另外,由于排序序列中数据的相对位置可能变化,所以希尔排序是一种不稳定的排序
。