直接插入排序
直接插入排序: 其实直接插入排序的思路非常简单,就是把待排序的记录按其关键字的大小主干插入到一个已经排好序的序列中,知道所用的记录查完为止。类似于扑克牌,每取一张就会将会比对大小将其插入到手中牌群的合适位置,这样手上牌群始终有序;直到扑克牌取完;
流程:
- 先设置一个(哨兵)变量保存要插入的值;
- 插入数据从后面开始比较,如果大于前面的就记录下标,并将数据后移,直到插入数据碰到比它小的。
- 将临时变量赋值给当前下标
- 重复上述,知道循环结束
void IsertSort(int* arr,size_t n)
{
for(int i = 1; i < n; i++)
{
int key = arr[i];//设置哨兵保存变量
int end = i-1;
while(end >= 0 && arr[end] > key)
{
arr[end + 1] = arr[end];
--end;
}
arr[end+1] = key;
}
}
时间复杂度为 O(N^2)
空间复杂度为 O(1)
稳定性:稳定(假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,则稳定)
使用场景:数据量小且接近有序数据,不常用
希尔(shell)排序
希尔(shell)排序: shell排序是直接插入排序的优化,我们知道直接插入排序适用的范围是数据量较小且接近有序的场景,但是现实中情况往往不容乐观,数据量大且杂乱无章是常态,那么在使用直接插入排序那么难免会降低效率,所有提出一种缩小增量的方法,在逻辑上讲一个数据量大的数组分为若干个小的数组,逐个进行直接插入排序,那么整个大的数组也将接近有序,左后在进行一个直接插入排序这样就提好了效率。
流程:
- 设置一个合适的增量gap,将数组中相同gap的元素视为一个组,然后进行直接插入排序,直到数组边界
- 然后逐渐缩小增量gap,重复上述排序
- 知道gap为1时,数组元素趋近有序,相当于对完整数组进行一次直接插入排序
void ShellSort(int* arr,size_t n)
{
int gap = n;//设置增量
while(gap > 1)
{
gap = gap / 3 + 1;//经过大量数据验算,gap最佳定值方式
for(int i = 0; i < n; i++)
{
int key = arr[i];
int end = i - gap;
while(end >= 0 && key < arr[end])
{
arr[end + gap] = arr[end];
end -= gap;
}
arr[end+gap] = key'
}
}
}
时间复杂度为 O(N ^1.3 ~ N ^2)
空间复杂度为 O(1)
稳定性 :不稳定
使用场景:是直接插入的优化,gap>1都是预排序,==1数组接近有序,较为常用