数据结构与算法-插入排序

132 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

前言

学习了解冒泡排序和选择排序之后,这次再学习一种排序-插入排序。在之前排序效率上看都是O(N2N^2),接着来看看插入排序是在最差情况下效率上是否有所提升。

插入排序

插入排序对于少量数据的数组来说是较为有效的算法。

索引0索引1索引2索引3索引4索引5
763915
  1. 首先指向索引1将数据用临时变量先保存,然后进行平移操作(下后比较,其实就是和索引0比较)。若比索引0小就交换位置。
  2. 接着指向索引2索引1索引0依次比较,直到发现比它们都小平移到索引0
  3. 接着指向索引3和前面索引依次比较重复以上操作。
  4. 如上操作重复进行直到指向索引5后依次表结束操作。

原理

插入排序基础思想是取数组中的数据与其前方数据做大小比较,若数据大小比前方数据小时做平移操作直至它不是最小值为止。

468597

指针指向索引1数值为6,和索引0数值为4比较,因为比索引0大不做平移操作;指针指向索引2数值为8,和索引1数值为6比较还是比大不做平移。指针指向索引3数值为5比前面数值都小平移到索引1之前数据都往后移动....指针指向索引5...平移到索引3在把前面值往后移动结束操作。

image.png

算法代码

基础版

i表示循环次数,j是指向当前下标前方索引个数。指向当前下标与前方索引数据比较。

void main(){
    int i,j;
    int[] datas;
    for(int i=1;i<=datas.length - 1;i++){
        for(int j=i-1;j>=0;--j){
            if(datas[j] > datas[j+1]){ //小于前方数值做数值交换
                int temp = datas[j];
                datas[j] = datas[j + 1];
                datas[j + 1] = temp;
            }else{
                 // 若下标比前方数值大 就直接结束当次循环
                break;
            }
        }
    }
}

假设N个数据执行以上算法1+2+3+4...+N1=N(N1)/21+2+3+4...+(N - 1)= N*(N-1)/2可推导大O记法为O(N2/2N^2/2),最终还是O(N2N^2)。最好的情况下数组是正序排布,比较次数是N-1,大O记法为O(N)

升级版

优化版本是将交换改换成赋值形式,代码更为简洁高级。

void main(){
    int j,temp;
    int[] datas;
    for(int i=1;i<=datas.length - 1;i++){
        temp = datas[i]; // 暂存需要待插入值
        j = i - 1;
        while(j >= 0 && temp < datas[j]){ //待插入值和序列比较大小
            datas[j+1] = datas[j]; // 后移序列
            --j;
        }
        datas[j+1] = temp; // 待插入值插入
    }
}

如何选择排序算法

在最坏情况下选择排序是比插入排序效率更高,但如果考虑到平均情况选择哪种算法就需要再想想了。插入排序性能在不同情况下差异也比较大,最坏情况是(N2N^2)、平均情况是(N2/2N^2/2)、最好情况是(NN);选择排序无论哪种情况下都是(N2/2N^2/2),因为选择排序每轮遍历都需要比较右边所有值。若在数组大致有序选择插入排序可能会比较高效,若是大致逆序数组选择选择排序可能会比较快。

总结

插入排序和冒泡排序比较上看效率会好一些,但在大数据使用中效率并不高,也不推荐使用。目前了解了冒泡排序、选择排序以及插入排序,虽然说它们处理排序效率并不高但作为算法入门是必知必会的经典算法。