排序算法 插入排序 InsertSort -- C语言实现
插入排序
描述
插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。
应用分析
插入排序适用于已经有部分数据已经排好,并且排好的部分越大越好。一般在输入规模大于1000的场合下不建议使用插入排序
时间复杂度
- 在插入排序中,当待排序数组是有序时,是最优的情况,只需当前数跟前一个数比较一下就可以了,这时一共需要比较N- 1次,时间复杂度为
O(N)
。 - 最坏的情况是待排序数组是逆序的,此时需要比较次数最多,总次数记为:1+2+3+…+N-1,所以,插入排序最坏情况下的时间复杂度为
O(N^2)
。 - 平均来说,A[1..j-1]中的一半元素小于A[j],一半元素大于A[j]。插入排序在平均情况运行时间与最坏情况运行时间一样,是输入规模的二次函数 [1]。
特点:越往后,最坏需要的循环次数越多
时间复杂度1+2+3+4+n ~= n²
空间复杂度
插入排序的空间复杂度为常数阶O(1)。
算法步骤
将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
代码实现
注:以升序举例,排序数组为a[n]
算法思想:前n-1个有序数组,第n个为待排序(插入)元素,通过插入让第n个待排序数组也有序.
具体状态:
-
a[n-1]<a[n]
,有序 -
至少存在
a[n] < a[0],a[1],...,a[n-1]
,需要排序其中边界为
an[n]<a[0]
-
n == 1
:边界一个一定是有序的
-
i == n-2为最后一组有序数组的边界,n-1为最后一个需要插入的元素
满足稳定排序写法:
a[n]<a[n-1]
时才插入(小于才插入)
不稳定排序写法:
a[n]<=a[n-1]
时插入(相等时也交换)
插入排序特征:
-
迭代范围:从小到大
-
插入过程范围:从大到小
-
插入过程:挪动覆盖
例图
//直接插入排序
void InsertSort(int* a, int n)
{
assert( a && n ); //a不能为空且n不能为0 (当n为0,则i为最大整型值,错误)
//当n==1,边界
//当n>1,执行算法
//i==n-2,最后一次插入
for (int i = 0; i < n - 1; i++) {
int end = i;
int tmp = a[end + 1]; //因挪动会将end+1位置覆盖,因此使用tmp保存准备插入的元素
while (end >= 0) {
//挪动覆盖
if (a[end]>tmp){ // a[end]>tmp升序, a[end]<tmp降序
a[end + 1] = a[end];
end--;
}
else {
break;
}
}
//挪动覆盖方式,结束时将tmp写入到目标位置
a[end + 1] = tmp;
}
}
//降序实现
void InsertSort(int* a, int n)
{
assert(a && n); //a不能为空且n不能为0 (当n为0,则i为最大整型值,错误)
for (int i = 0; i < n - 1; i++) {
int end = i;
int tmp = a[end + 1];
while (end >= 0) {
if (a[end]<tmp){ // a[end]>tmp升序, a[end]<tmp降序
a[end + 1] = a[end];
end--;
}
else {
break;
}
}
a[end + 1] = tmp;
}
}
本文来自博客园,作者:HJfjfK,原文链接:https://www.cnblogs.com/DSCL-ing/p/18344192