数据结构-直接插入排序

直接插入排序是一种简单直观的排序算法,适用于小数据量或基本有序的数据。它通过将每个待排序元素插入到已排序的子序列中合适的位置来构建最终的有序序列。文章详细介绍了算法思想、图形描述、不同版本的代码实现,并分析了时间复杂度和稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

直接插入排序

直接插入排序:

是一种比较简单直观的排序算法,适用处理数据量比较少或者基本有序的数据。

算法思想:

每次将一个待排序的记录,按其关键字大小插入到前面已有序的子序列中合适位置,直到全部记录插入完为止。 

不妨设设数组为 a[n]:

(1)初始时,a[0] 自成一个有序区间,无序元素为 a[1]...a[n]。 

(2)将 a[i] 插入到有序序列 a[0]...a[i-1] 中合适位置,形成 a[0]...a[i] 的有序序列。

(3)重复第二步直到最后需插入的元素 a[n-1] 插入到前面的有序序列中合适位置,整个插入排序完成。

图形描述: 

我们以待排序列 {48,62,35,77,55,14,35,98} 为例来看看直接插入排序的实现过程,其中大括号内是已经有序的子序列,大括号中紫色字体标识的元素是子序列中最后插入的元素。

  1.  {48}        62        35        77        55        14        35        98
  2.  {48         62}       35        77        55        14        35        98
  3.  {35         48        62}       77        55        14        35        98
  4.  {35         48        62        77}       55        14        35        98
  5.  {35         48        55        62        77}       14        35        98
  6.  {14         35         48        55        62        77}      35        98
  7.  {14         35         35        48        55        62       77}      98
  8.  {14         35         35        48        55        62       77       98}

代码实现: 

首先我们给出严格按照定义书写的代码(由小到大排序):

void InsertSort(int a[],int n)
{
	int i, j, k;
	for (i = 1; i < n;++i)
	{
		//首先待插入元素a[i]在前面a[0,...,i-1]的有序序列中找到自己的位置
		for (j = i - 1; j >= 0;--j)
			if (a[j] < a[i])
				break;

		//此时待插入元素a[i]已经找到自己的位置,但它的位置还被别的元素占着
			if (a[j] != i - 1)
			{
				//将比a[i]大的元素向右移动(从小到大排列)
				int tmp = a[i];
				for (k = i - 1; k>j; --k)
					a[k + 1] = a[k];

				//将a[i]放到正确的位置处(下表为k处)
				a[k+1] = tmp;
			}
	}
}

现在进行一下改进,将 a[i] 寻找自己自己位置和有序的子序列中比 a[i] 大的数据后移这二个步骤合并。即每次a[i]先和前面一个数据a[i-1]比较,如果a[i] > a[i-1]说明a[0…i]也是有序的,无须调整。否则就令j=i-1,temp=a[i]。然后一边将数据a[j]向后移动一边向前搜索,当有数据a[j]<a[i]时停止并将temp放到a[j + 1]处。

void InsertSort(int a[], int n)
{
	int i, j;
	for (i = 1; i < n; ++i)
	{
		if (a[i] < a[i - 1])
		{
			int tmp = a[i];

			for (j = i - 1; j>=0 && a[j]>tmp;--j)
				a[j + 1] = a[j];

			a[j + 1] = tmp;
		}

//在第一层for循环内部以下注释掉的代码也是可以的,二者没有本质的区别
//		int tmp = a[i];
//		for (j = i - 1; j >= 0; --j)
//		{
//			if (a[j] > tmp)
//			{
//				a[j + 1] = a[j];
//			}
//			else
//				break;
//		}
//		a[j + 1] = tmp;

	}
}

再对将a[j]插入到前面a[0…j-1]的有序区间所用的方法进行改写,用数据交换代替数据后移。如果a[j]前一个数据a[j-1] > a[j],就交换a[j]和a[j-1],再j--直到a[j-1] <= a[j]。这样也可以实现将一个新数据新并入到有序区间。

void InsertSort(int a[], int n)
{
	int i, j;
	for (i = 1; i < n; i++)
	{
		for (j = i - 1; j >= 0 && a[j] > a[j + 1]; j--)
			Swap(a[j], a[j + 1]);
	}
}

直接插入排序中第一层 for 循环以 i= 0 开始,内部以 while 循环实现数据的比较、移动和边界的控制又是一种思想的体现。

void InsertSort(int* arr, int n)
{
	assert(arr);

	for (int i = 0; i < n-1;++i)
	{
		//将tmp插入以end为结束的有序区间
		int end = i;
		int tmp = arr[end + 1];

		while (end >= 0 && arr[end] > tmp)
		{
			arr[end + 1] = arr[end];
			--end;
		}

		arr[end + 1] = tmp;
	}
}

在直接插入排序代码实现这块提供了多种实现方式,从原始的最基本的算法思想实现到步步改进,从不同维度和实现方式中理解直接插入排序,相信会更好吧哈哈哈

时间复杂度和空间复杂度:

下面讨论最坏时间复杂度,即所有元素倒序排列

对于 n 个元素,首先外层的 for 循环要执行 n-1 次,内层循环是根据 i 来决定的,i = 1,循环1次;i = 2,循环2次;...;i = n-1;循环 n-1 次。总共加起来就是:

1+2+\cdots +(n-1) = \frac{n(n-1))}{2} = \frac{1}{2}(n^{2}-n)

根据复杂度的计算规则,保留高阶项并去掉系数得直接插入排序的时间复杂度为O(N^{2})

直接插入排序的各种时间复杂度及空间复杂度
算法名称时间复杂度最坏时间复杂度平均时间复杂度最好时间复杂度空间复杂度
直接插入排序O(N^{2})O(N^{2})O(N)O(1)

稳定性:

是稳定的,因为在比较的时候,当两个数相等时不会进行移动,前后两个数的次序不会发生改变。

注意:算法的稳定性是相对的,任何稳定的算法是可以改变为不稳定算法的。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值