1. 基本思想
插入排序是一个简单的排序,其基本思想是将待排的数据逐个插入到一个有序的的序列当中。在我们打扑克牌的时候用的就是这个思想。
2. 直接插入排序
2.1 实现
当插入第n个数据的时候,前n-1个数据已经排好序了,此时,只需要将该数据和n-1、n-2……个数据比较,直到找到比它大/小的数据(根据你排升序还是降序)然后插到它后面,没找到的时候将数据往后移。
代码实现
// 插入排序(升序)
void InsertSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)
{
int end = i;
int value = a[end + 1];
//找到比val位置小的那个
while (end >= 0)
{
if (a[end] <= value)
break;
else
a[end + 1] = a[end];
end--;
}
//插到后面
a[end + 1] = value;
}
}
2.2 时间和空间复杂度分析
时间复杂度:
考虑到最坏的情况,就是给出要排列的序列是逆序,每次的while循环都要走到最后,故时间复杂度可以写成 1 + 2 + 3 + …… + n - 1,为O(N^2)
最好的情况就是顺序,时间复杂度就是O(N)
空间复杂度:
这个没什么好说的,没使用额外的数组或者栈空间,为O(1)
2.3 特性
- 给出的排序数组越接近有序,该方法的效率会很高
- 该排序是稳定的
3. 希尔排序
希尔排序又称缩小增量法,其基本思想是先选定一个距离gap(自身距自身的gap为0),将距离为gap的数据归为一组,然后将每组都使用插入排序排好序,循环该过程,直到gap为1的一趟排完。
3.1 实现
// 希尔排序(升序)
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
//保证gap最后一次一定为1
gap = gap/3 + 1;
for (int i = 0; i < n - gap; i++)
{
int end = i;
int value = a[end + gap];
while (end >= 0)
{
if (a[end] <= value)
break;
else
a[end + gap] = a[end];
end -= gap;
}
a[end + gap] = value;
}
}
}
3.2 时间和空间复杂度分析
时间复杂度:
希尔排序的分析是一个复杂的问题,因为它的时间是所去gap的序列函数。所公认的几个时间复杂度为O(n^1.5) / O(n^1.25)~ O(1.6n^1.25)
空间复杂度:
O(1)
3.3 特性
- 希尔排序是对直接插入排序的优化。
- 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。
- 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定。