直接插入排序
一开始全部将数据当做无序的,每一次从待排序队列中取出一个值,放到我们已经排序好的队列中,然后将其调整有序,然后再从待排序队列中取出一个值,直到待排序队列中没有值,然后结束。
调整规则:
将待插入的值和有序队列的所有值挨个比较(从右到左),找到一个小于或者等于自己的值,则停下来,插入到当前位置的下一个位置
示例:
有一组数据nums = {12,2,9,8,18,7} , 第一趟排序只有一个数据,那么我们默认其是有序的,从第二趟开始,我们从待排序的数据中取出一个值,从有序的数据中从左到右,从小到大依次比较,找到一个小于或者等于自己的值,停下来插入到其下一个位置,如下图所示:
代码
void InsertSort(int* arr, int len)
{
assert(arr != NULL);
for (int i = 1; i < len ;i++)//跑的次数
{
int j;
int tmp = arr[i]; //指向待插入的值
//j 指向 这一趟开始的时候的已排序好的队列中的最后一个值的下标
for (j = i - 1; j >= 0;j--) //待插入的值和已排序队列的挨着比较
{
if (arr[j] <= tmp)
{
break;
}
else
{
arr[j + 1] = arr[j];
}
}
arr[j + 1] = tmp;
}
}
测试
特点
1.时间复杂度过大
O
(
n
2
)
O(n^2)
O(n2) —> 合适的使用场景:
n
n
n比较小的时候
2.如果数据越来越有序,则直接插入排序效率越高
希尔排序
希尔排序是对直接插入的排序优化,又称“缩小增量排序”,主要根据直接插入排序的数据越有序,直接插入排序效率越高的特点进行改良的,
基本思想
先将整个待排记录序列分割成若干的子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
示例
原始数据:12 2 9 8 5 88 89 99 10 7 17 77 66 89 10 21
按照增量[5,3,1] 进行分组排序,
注:增量分组并不固定,但是最后一次分组必须为1,也就是相当于最后一次是一个直接插入排序。
第一次排序按照增量5进行分组然后排序
第二次排序按照增量3进行分组然后排序
可以看出两次分组之后,数据会比之前更加有序一点
第三次排序按照增量1进行分组然后排序
代码
//希尔排序
void Shell(int arr[], int len, int gap) //一次希尔排序
{
for (int i = gap; i < len; i++)
{
int tmp = arr[i];
int j;
for (j = i - gap; j >= 0; j=j-gap)
{
if (arr[j] <= tmp)
{
break;
}
else
{
arr[j + gap] = arr[j];
}
}
arr[j + gap] = tmp;
}
}
void Shellsort(int arr[], int len)
{
int gap[] = { 5,3,1 };
int gap_len = sizeof(gap) / sizeof(gap[0]);
for (int i = 0; i < gap_len; i++)
{
Shell(arr, len, gap[i]);
}
}
测试
算法复杂度分析
希尔排序的时间复杂度和增量数组有关,所有时间复杂度大致为 O ( n 1.3 − n 1.7 ) O(n^{1.3}-n^{1.7}) O(n1.3−n1.7),空间复杂度为 O ( 1 ) O(1) O(1)