如何优雅的实现插入排序

425 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

前言

这是"优雅系列"的第四篇,让我们一起来手撕插入排序。

1. 如何优雅的实现二分法查找

2. 如何优雅的实现冒泡排序

3. 如何优雅的实现选择排序

算法描述

  1. 将数组分为两个区域,排序区域的和未排序区域,每一轮从未排序的区域中选出第一个元素,有序的放入排序区域中
  2. 重复以上步骤,直到整个数组有序

算法实现

    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 循环的外面定义。

插入排序和选择排序比较

  1. 平均时间复杂度都是 n 的平方
  2. 大部分情况下,插入算法都略优于选择算法
  3. 有序集合插入算法的时间复杂度为 O(n)
  4. 插入排序属于稳定性排序算法,选择算法属于不稳定排序算法

最后

感觉插入算法和选择算法的思想非常的接近,选择是从未排序的区域中拿一个最小的,放在排序区域的最后就行,而插入是从未排序的区域中拿第一个,有序的插入到已排序的区域里。越看越感觉是一对对称的兄弟,而插入算法在感觉上会更胜一筹,因为它没有交换的逻辑。