【算法】插入排序

算法-插入排序


前置知识
  • C++入门
  • 二分查找
  • 链表

思路

我们现在有一个序列,怎么对它排序?
这是一个非常经典的问题,这里我们使用一个经典的算法——插入排序解决。

这里有一个序列,要对它升序排序
3 5 1 6 4 2 \begin{array}{cc} 3&5&1&6&4&2 \end{array} 351642
我们把序列分为有序序列无序序列
这里,我们将无序序列用红色表示,有序序列用蓝色表示
很显然,这里的所以元素默认都是无序的,换句话说,所有元素都属于无序序列。
3 5 1 6 4 2 \begin{array}{cc} \red3&\red5&\red1&\red6&\red4&\red2 \end{array} 351642
然后将无序序列开头元素插入有序序列中
3 5 1 6 4 2 \begin{array}{cc} \blue3&\red5&\red1&\red6&\red4&\red2 \end{array} 351642
重复以上操作
3 5 1 6 4 2 1 3 5 6 4 2 1 3 5 6 4 2 1 3 4 5 6 2 1 2 3 4 5 6 \begin{array}{cc} \blue3&\blue5&\red1&\red6&\red4&\red2 \end{array}\\\begin{array}{cc} \blue1&\blue3&\blue5&\red6&\red4&\red2 \end{array}\\\begin{array}{cc} \blue1&\blue3&\blue5&\blue6&\red4&\red2 \end{array}\\\begin{array}{cc} \blue1&\blue3&\blue4&\blue5&\blue6&\red2 \end{array}\\\begin{array}{cc} \blue1&\blue2&\blue3&\blue4&\blue5&\blue6 \end{array} 351642135642135642134562123456
这就是插入排序!


具体实现

插入排序有两种版本。

当我们使用数组实现的时候,可以使用二分查找优化达到 O ( log ⁡ n ) O(\log n) O(logn),但是插入的时候会达到 O ( n ) O(n) O(n),导致时间复杂度达到 O ( n 2 ) O(n^2) O(n2)。所以不如使用线性查找来的好。

当我们使用数组实现的时候,可以将插入优化达到 O ( 1 ) O(1) O(1),但是查找的时候不支持二分,会达到 O ( n ) O(n) O(n),导致时间复杂度达到 O ( n 2 ) O(n^2) O(n2)


算法参数

数组版本:

  • 平均时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 最好时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 最坏时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( n ) O(n) O(n)
  • 排序稳定性:稳定

链表版本:

  • 平均时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 最好时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 最坏时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( n ) O(n) O(n)
  • 排序稳定性:稳定

极端情况

对于数组版本,可以使用降序序列,链表版本反之,使用升序序列(仔细想一想为什么)。


优化

无法优化

插入排序分为两个过程,查找和插入。
正如前文讲的,
查找可以使用二分查找降到 O ( log ⁡ n ) O(\log n) O(logn),但是会使得插入升到 O ( n ) O(n) O(n)
插入可以使用链表维护降到 O ( 1 ) O(1) O(1),但是会使得查找升到 O ( n ) O(n) O(n)


实现代码
  • 数组版本
void InsertionSort(int a[],int n){//插入排序
    for (int i=2;i<=n;i++){
        int tmp=a[i],pos=i;//pos为指针
        while (pos-1&&a[pos-1]>tmp)
        	a[pos]=a[pos-1],pos--;
        a[pos]=tmp;//将a[i]移到pos处
    }
}
  • 链表版本
void InsertionSort(int a[],int n){
	int h,r[100010];h=1;r[0]=1;
    for (int i=2;i<=n;i++){
        int pos=0;
        while (r[pos]&&a[r[pos]]<=a[i]) pos=r[pos];
        if (!pos) r[i]=h,h=i;
        else r[i]=r[pos],r[pos]=i;
    }
    int k=1,tmp[100010];
    for (int i=h;i;i=r[i]) tmp[k++]=a[i];
    for (int i=1;i<=n;i++) a[i]=tmp[i];
}

练习
  • CSP-J 2021 插入排序

你可能感兴趣的:(算法,#,排序,算法,排序算法)