排序算法 插入排序 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个待排序数组也有序.

具体状态:

  1. a[n-1]<a[n] ,有序

  2. 至少存在a[n] < a[0],a[1],...,a[n-1],需要排序

    其中边界为an[n]<a[0]

  3. n == 1:边界

    一个一定是有序的

  4. i == n-2为最后一组有序数组的边界,n-1为最后一个需要插入的元素

满足稳定排序写法:

a[n]<a[n-1]时才插入(小于才插入)

不稳定排序写法:

a[n]<=a[n-1]时插入(相等时也交换)

插入排序特征:

  • 迭代范围:从小到大

  • 插入过程范围:从大到小

  • 插入过程:挪动覆盖

例图

image-20240811161411931

//直接插入排序
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;
	}
}
posted @ 2024-08-06 16:00  HJfjfK  阅读(65)  评论(0编辑  收藏  举报