算法系列(一):插入排序

199 阅读3分钟

插入排序介绍

插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加1的有序数据,算法适合用于少量数据的排序,时间复杂度为O(n^2). 是稳定的排序方法。 插入算法把要排序的数组分成两个部分:第一个部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置), 而第二部分就只包含一个元素(即待插入元素), 在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中.

插入排序的基本思想是:每步将一个待排序的记录,按照其关键码值的大小插入到前面已经排序的文件中适当位置上,直到全部插入完为止

插入排序代码如下

package com.nineweeks.simplesort;

/**
 * 插入排序
 *
 * 规则:局部有序
 *     首先我们标记一个值,使其左边的排列是有序的,右边是无序的,
 *     然后,我们让标记的值出列,将其插入到左边的合适位置,
 *     将左边的数值右移一位,然后将标记右移一位,
 *     以此下去,直到有序
 * 插入排序 每经历一次循环,被标记数值的左边都局部有序
 *
 * 插入排序的时间复杂度:
 *     插入排序平均需要n(n-1)/4次比较,复制的次数大致等于比较的次数,
 *     但是复制的执行效率要比交换的执行效率要高,所以插入排序的执行
 *     速度比冒泡排序快一倍,比选择排序稍快
 *     大O表达式:O(n2)
 *
 *
 * @author NineWeek
 * @date 2020/05/07 15:32
 **/
public class InsertSort {

    private long[] a;
    private int nElems;

    public InsertSort(int max){
        a = new long[max];
        nElems = 0;
    }

    public void insert(long value){
        a[nElems++] = value;
    }

    public void insertSort(){
        int in, out;
        // 左边的局部有序最少需要一个元素进行比较
        for (out = 1; out < nElems; out++) {
            long temp = a[out];
            in = out;
            //从标记位置从右往左,以此进行比较
            while (in > 0 && a[in-1] >= temp){
                a[in] = a[in-1];
                --in;
            }
            a[in] = temp;
        }
    }
    /**
     * 数组的展示方法
     */
    public void display(){
        for (int i = 0; i < nElems ; i++) {
            System.out.print(a[i]+" ");
        }
        System.out.println();
    }

    public  static  void main(String[] args){
        InsertSort  sort = new InsertSort(100);
        sort.insert(77);
        sort.insert(99);
        sort.insert(44);
        sort.insert(55);
        sort.insert(22);
        sort.insert(88);
        sort.insert(11);
        sort.insert(80);
        sort.insert(66);
        sort.insert(33);
        sort.display();
        System.out.println("=============");
        sort.insertSort();
        sort.display();
    }
}

输出结果

插入排序算法分析:

分析最坏的情形,数组逆序排列:最大元素在首位,最小的元素在尾部.观察代码,嵌套循环的部分,对全部的时间进行求和,我们假设每一步的原子性操作都消耗常数值时间,忽略细节,进行渐进化分析, out 的值从1开始,一直到nElems,用j表示out,用n表示nElems(数组长度),对每次的内部循环进行求和。

公式如下:

\begin{align}
  T(n) = \sum_{j=1}^{n}\Theta{(j)}=\Theta {(n^2)}
\end{align}

这是一个算数级数

\begin{align} 1+2+3....+n =\frac{n(n+1)}{2}\end{align}

插入排序快吗?

对于小的n,插入排序是很快的,但对于很大的n,插入排序就不是那么回事了!!