假设红竖线前的元素全部排好序,红线后面的数即为要插入的数据,红线依次往后移,假设end为排好序的最后一个数字,end+1即为要插入的数字,一次插入时,end与要插入的数字依次比较,之后end--,直到end小于0后循环停止,进入下一次的插入数据,故让end等于for循环里的i即可,一次插入之后end就向后移一位,循环次数为n-2(若为n-1,end+1就会越界)。
//插入排序,以升序为例
//时间复杂度为O(N^2)
//逆序的情况最坏(最坏的情况下的次数为时间复杂度e)
void InsertSort(int* a, int n)//n为数组元素的个数
{
//[0,end]有序,end+1位置的值插入[0,end],让[0,end+1]有序。
//控制循环次数,防止数组越界
for (int i = 0; i < n; i++)
{
int end = i;
//记录end+1处的值,防置被覆盖之后找不到原始数据
int temp = a[end + 1];
while (end >= 0)
{
if (a[end] > temp)
{
a[end + 1] = a[end];
end--;
}
else
break;
}
a[end + 1] = temp;
}
}
希尔排序是将数组里的元素间隔为gap的数据分为一组,将本组的数据排序,如上图,此时1 4 7 0为一组,2 5 8为一组,3 6 9为一组,分别将每组进行排序,最后会得到相比原来较为有序的数组,其算法和插入排序类似,只是每次分组并排序后的gap会越来越小,直到为1,就是直接插入排序。总体来说,希尔排序是将数组变为接近有序的数组,然后再进行直接插入排序,这样大大提高了代码效率。
- 多组间隔为gap的预排序,gap越大,大的数可以越快的到后面,小的数可以越快的到前面,
- gap越大,预排完越不接近有序,
- gap越小越接近有序
- gap=1时,就直接是插入排序
//希尔排序
//直接插入排序的优化
//1.先对数组进行预排序,使数组接近有序 //预排序:分组排序,间隔为gap为一组,gap是几就分成几组
//2.直接插入排序
//平均时间复杂度:O(N^1.3)
void ShellSort(int* a, int n)
{
int gap=n;
while (gap > 1)
{
gap = gap / 2;//时间复杂度为log以2为底N的对数
//gap很大时,预排序时间复杂度为O(N)
//gap很小时,此时数组已经接近有序,时间复杂度可近似看成O(N)
for (int i = 0; i < n - gap; i++)
{
int end = i;
int temp = a[end + gap];
while (end >= 0)
{
if (a[end] > temp)
{
a[end + gap] = a[end];
end -= gap;
}
else
break;
}
a[end + gap] = temp;
}
}
}