插入排序:扑克牌式的排序算法!

目录

一.引言

二.核心思想

三.性能分析

3.1 时间复杂度

3.2 稳定性

四. 结语


一.引言

       想象一下你正在整理手中的扑克牌:你总是拿起下一张牌,然后将它插入到左手边已经整理好的牌堆中的正确位置。插入排序的工作原理与此如出一辙。它将一个数组(或列表)分为“已排序”和“未排序”两个部分,然后逐一将未排序部分的元素插入到已排序部分的正确位置。

       插入排序因其简洁性、稳定性,以及在处理小规模或“几乎有序”数据时所展现出的高效率,而在实际应用中占据着一席之地。

二.核心思想

       插入排序的核心在于原地构建有序序列,空间复杂度为O(1)。它从第二个元素开始,将其视为待插入的“键”(tmp),然后将这个“键”与前面已排序的序列中的元素逐一比较,如果比它大,就向后移动一位,直到找到一个小于或等于“键”的元素的位置,然后将“键”插入到该位置。

void InsertSort(int* arr, int n)
{
	// 外层循环:遍历未排序部分的第一个元素
	// i < n - 1 是因为我们将 arr[i+1] 作为待插入元素
	for (int i = 0; i < n - 1; i++)
	{
		int end = i; // end 指向已排序序列的最后一个元素的下标
		int tmp = arr[end + 1]; // tmp 是待插入的“键”

		// 内层循环:在已排序序列中寻找 tmp 的合适位置
		while (end >= 0)
		{
			// 如果已排序元素 arr[end] 大于待插入的 tmp
			if (tmp < arr[end])
			{
				// 将 arr[end] 向后移动一位,为 tmp 腾出空间
				arr[end + 1] = arr[end];
				end--; // 继续向前比较
			}
			else
			{
				// 找到了一个小于或等于 tmp 的元素,停止比较
				break;
			}
		}
		// 将 tmp 插入到找到的正确位置(即 end + 1 的位置)
		arr[end + 1] = tmp;
	}
}

三.性能分析

3.1 时间复杂度

       插入排序的性能表现高度依赖于输入数据的初始状态,其时间复杂度可以从线性到平方级变化。

  • 最好情况O(N): 当数组已经完全有序时,插入排序达到它的最佳性能。在这种情况下,外循环每次迭代时,待插入的元素(tmp)只需与已排序序列的最后一个元素进行一次比较,内循环会立即终止。因此,总的操作次数与数组元素数量 n 成线性关系。

  • 最坏情况O(N²): 当数组完全逆序时,算法性能最差。在这种情况下:①要插入第 i 个元素时,它必须与前面已排序的 i-1 个元素全部进行比较,并且全部进行移动(或交换),才能到达它最终的位置。②外循环从第二个元素开始(i = 2 到 n),所以需要进行的比较总数大约是:

        这是一个等差数列求和公式:

        根据大 O 的渐进表示法(只保留最高次项,并忽略常数系数):

  • 平均情况 O(N²): 在随机排列的数组中,平均而言,待插入的元素需要移动大约一半的已排序元素。因此,平均情况的时间复杂度与最坏情况相似,也是O(N²)

总结: 插入排序在处理小规模数据或接近有序的数据集时表现出色,但在处理大规模且完全无序的数据时,其二次方的时间复杂度 O(N²) 会使其效率低于其他高效排序算法。

3.2 稳定性

       稳定性是指如果一个数组中有两个或多个具有相同键值(Key)的元素,在排序后,它们在原数组中的相对顺序不会改变

  • 例如,有一个数组 [5a, 3, 5b],其中 5a5b 的值相同,但 5a5b 的前面。

  • 如果排序后的结果是 [3, 5a, 5b],则该算法是稳定的。

  • 如果排序后的结果是 [3, 5b, 5a],则该算法是不稳定的。

        那稳定性有什么用呢?似乎相同的值在前在后对整体排序结果并没有影响。的确对于整数进行排序确实没有影响,但是对于结构体排序,稳定性就显得至关重要了。

struct Product {
    float price;     // 主要排序键:价格
    int relevance;   // 次要排序键:产品相关性评分(越高越好)
    // ... 其他信息(名称、销量等)
};

用户想实现这样的排序需求:首先按照价格(price)升序排列,如果价格相同,则按照相关性评分(relevance)降序排列。

产品ID价格(key)相关性(次序)原始顺序
A100951
B200802
C100703

第一次排序(按次要键): 先按相关性降序排序。

结果A(95)B(80)C(70)

A 和 C 仍然保持了 AC 前面的原始顺序)

第二次排序(按主要键):价格升序排序。

  • 价格为 100 的元素是 AC

  • 稳定排序算法会确保在处理价格相同的元素时,它们之间已经建立好的“相关性降序”顺序不被破坏。

产品ID价格相关性第一次排序后的顺序最终稳定排序结果
A1009511
C1007032
B2008023

如果第二次排序使用的是不稳定算法,那么在对 A 和 C 进行排序时,它可能会错误地交换 A 和 C 的相对位置,导致最终结果中价格相同的 C 跑到了 A 的前面,破坏了按相关性预先建立好的次序。

       根据以上总结,由于插入排序在遇到相等的元素时,会停止向前移动,并将待插入元素放置在原先那个相等元素的右侧,因此它保持了相等元素的相对顺序。所以,插入排序是稳定的


四. 结语

        插入排序以其优雅和直观性,在众多排序算法中占有一席之地。尽管在实际中并不会直接应用插入排序来解决复杂排序问题,但凭借其在处理小规模数据或接近有序的数据集时表现出色的特点,往往作为更复杂排序算法(如快速排序、归并排序)的辅助算法。

       笔者最近会快快更新完其他排序算法的!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值