插入排序的思想
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为
止,得到一个新的有序序列。
插入排序的特性
1. 元素集合越接近有序,直接插入排序算法的时间效率越高
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1),它是一种稳定的排序算法
4. 稳定性:稳定
在c++库中的sort中也应用到了插入排序。
插入排序的实现
void InsertSort(int *a, int n) // a指针为需要进行排序的数组的指针,n为需要排序的数组的数据个数
{
for (int i = 0; i < n - 1; ++i) // 把每个数都和前面的序列进行比较、插入,这里i不能到达n-1是为了防止越界
{
int end = i;
int tmp = a[end + 1]; // 备份本次循环准备要进行插入的值
while (end >= 0)
{
if (a[end] > tmp) // 如果该位置的值大于tmp则把该位置的值往后移动
{
a[end + 1] = a[end];
end--; // 让即将进行插入的值与前面的序列以此进行比较
}
else // 如果没满足上面if中的条件则代表找到了要进行插入的位置
{
break; // 结束循环准备进行值的插入
}
}
a[end + 1] = tmp; // 把值进行插入
}
}
单趟解释
假如我们要升序排序下面的数据,那么现在5就是我们要排序的数,对应上方代码的tmp
那么现在各个下标的位置如
然后开始执行循环中的逻辑,直到break之前数组内的状况是这样的
(出现两个7是因为上一次的循环把数据往后移动造成的,作为tmp的数字5已经备份了起来,所以这里这样覆盖也不会出现问题)
到这里的时候已经不满足a[end] > tmp的条件,于是乎结束循环并用之前tmp的值覆盖掉end+1指向的值。
覆盖完就像下面这样了
可见把5插入到前面之后也保持了前面数据的升序排序,往后也是以此类推直到把整个数组排序完。
插入排序的稳定性
首先要明确稳定性的含义是指排序完成之后,数组中相同的数之间的相对位置是否发生了改变,如果相对位置没有发生改变则代表稳定性好,反之。
从上面实现的逻辑可以看出,遇到和tmp相同的值的时候会在相同的值的后面进行插入,所以不会改变他们的相对位置。
插入排序的复杂度
就像上面所说的一样,插入排序的时间复杂度为O(n^2)
因为外循环和内循环的时间复杂度都为n,相乘起来便是n^2
由于排序过程开的新空间大小为常数,所以空间复杂度为O(1)