小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。
前言
这是"优雅系列"的第四篇,让我们一起来手撕插入排序。
算法描述
- 将数组分为两个区域,排序区域的和未排序区域,每一轮从未排序的区域中选出第一个元素,有序的放入排序区域中
- 重复以上步骤,直到整个数组有序
算法实现
private static void insert(int[] a){
for (int i = 1; i < a.length; i++) {
int readyToInsert = a[i];
int j;
for (j = i; j > 0 && a[j-1] > readyToInsert; j--) {
a[j] = a[j-1];
}
a[j] = readyToInsert;
}
}
看起来好像还挺简单的,但是这个实现还是需要解释一波,不然有点懵,外层循环控制的是未排序区域,每次都会取未排序区域的第一个,也就是 readyToInsert 准备插入到排序区域的值,插入到哪里呢?这个就是内层控制的了,可以看到这里其实是做了优化的,我会在内层循环结束找到一个插入的位置,然后执行真正的插入操作,这个 j 其实指向的就是排序区域待插入的位置。
i 指针是从左到右依次缩小未排序区域,而 j 指针是从右向左找到第一个比待插入元素小(或是等于)的位置。因为 j 需要在内层 for 循环结束之后执行真正的插入逻辑,所以需要在 for 循环的外面定义。
插入排序和选择排序比较
- 平均时间复杂度都是 n 的平方
- 大部分情况下,插入算法都略优于选择算法
- 有序集合插入算法的时间复杂度为 O(n)
- 插入排序属于稳定性排序算法,选择算法属于不稳定排序算法
最后
感觉插入算法和选择算法的思想非常的接近,选择是从未排序的区域中拿一个最小的,放在排序区域的最后就行,而插入是从未排序的区域中拿第一个,有序的插入到已排序的区域里。越看越感觉是一对对称的兄弟,而插入算法在感觉上会更胜一筹,因为它没有交换的逻辑。