可以理解为:将一个序列拆分为两个,前面那个序列是有序的,后面那个序列是无序的,每次比较都在无序序列中拿出一个元素,插入到有序序列中合适的位置,直到无序序列都被插入完为止
- 就好比我们打扑克一样,每次抓来一张牌,我们都要将它插入到合适的位置,来使手里的牌有序
例如:
目前有一个序列(5, 2, 0, 1, 3, 1, 4)
- 首先,我们将这个序列当做两个来看
- 前面是有序的:(5),(因为一个元素一定是有序的,所以初始时这样划分)
- 后面是无序的:(2, 0, 1, 3, 1, 4)
- 我们每次都在后面的序列中拿出首元素和前面那个序列中的元素比较(前面的元素反向遍历),并插入到前面序列中合适的位置
第一趟排序:
- 2比5小,所以插入到5前面
- (2, 5)(0, 1, 3, 1, 4)
第二趟排序:
- 0比5小,还比2小,所以插入到 2 前面
- (0, 2, 5)(1, 3, 1, 4)
第三趟排序:
- 1比2小,但比0大,所以插入到0和2中间
- (0, 1, 2, 5)(3, 1, 4)
第四趟排序:
- 3比5小,但比2大,所以插入到2和5中间
- (0, 1, 2, 3, 5)(1, 4)
第五趟排序:
- 1比2小,但和1相等,所以插入到1和2中间
- (0, 1, 1, 2, 3, 5)(4)
第六躺排序:
- 4比5小,但比3大,所以插入到3和5中间
- (0, 1, 1, 2, 3, 4, 5)
排序结束,此时已经是一个有序的序列了
Java代码
package algorithm;
public class Sort {
// 直接插入排序
public static void insertSort2(int[] array) {
for (int i = 1 ; i < array.length ; i++) {
int j;
// 找到比 array[i] 还小的元素的下标,然后将 array[i] 插入到它后面
for (j = i ; j > 0 ; j++) {
// 如果此元素 > array[i],就将这个元素后移一位
// array[j-1] 即为有序序列中的最后一个元素,
// 也就是要比较的第一个元素(因为是倒序遍历)
if (array[i] < array[j - 1]) {
array[j] = array[j - 1];
}
}
// 将 array[i] 插入到此位置
array[j] = array[i];
}
}
public static void main(String[] args) {
int[] array = new int[]{5, 2, 0, 1, 3, 1, 4};
Sort.insertSort(array);
// 打印数组
for (int i = 0 ; i < array.length ; i++) {
System.out.print(array[i] + " ");
}
}
}
Java代码(另一种写法)
其实两种思想是一样的
- 上面那种是先通过不断与前一个比较,找到要插入的位置,最后将元素插入进去
- 下面这种是将要插入的元素,不断与前一个比较,然后一点点交换到要插入的位置
下面这种比上面那种方法少了插入那一步,因为在比较的过程中就已经交换过去了
package algorithm;
public class Sort {
// 直接插入排序
public static void insertSort(int[] array) {
for (int i = 1 ; i < array.length ; i++) {
for (int j = i ; j > 0 ; j--) {
if (array[j] < array[j - 1]) {
int temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
}
public static void main(String[] args) {
int[] array = new int[]{5, 2, 0, 1, 3, 1, 4};
Sort.insertSort(array);
// 打印数组
for (int i = 0 ; i < array.length ; i++) {
System.out.print(array[i] + " ");
}
}
}
时间复杂度
最好情况:O(n),数组有序,每次我们仅需判断前面的一个元素即可
平均情况:O(n²)
最坏情况:O(n²),数组倒序,每次我们都需要遍历整个前面的有序序列才可