• 经典排序算法学习笔记三——插入排序


    插入排序

    工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

    插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

     

    数据结构 数组
    最差时间复杂度 O(n^2)
    最优时间复杂度 O(n)
    平均时间复杂度  O(n^2)
    最差空间复杂度 总共 O(n) ,需要辅助空间O(1)

       

              

    https://zh.wikipedia.org/wiki/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F#.E7.AE.97.E6.B3.95.E6.8F.8F.E8.BF.B0

    1、算法思想

    插入排序都采用in-place在数组上实现。

    1. 从第一个元素开始,该元素可以认为已经被排序
    2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
    3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
    4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
    5. 将新元素插入到该位置后
    6. 重复步骤2~5

     2、伪代码

    mark first element as sorted
    for each unsorted element
      'extract' the element
      for i = lastSortedIndex to 0
        if currentSortedElement > extractedElement
          move sorted element to the right by 1
        else: insert extracted element

    3、C实现

    void insertion_sort(int arr[], int len) {
        int i, j;
        int temp;
        for (i = 1; i < len; i++) {
            temp = arr[i]; //與已排序的數逐一比較,大於temp時,該數向後移
            for (j = i - 1; j >= 0 && arr[j] > temp; j--) //j循环到-1时,由于[[短路求值]](http://zh.wikipedia.org/wiki/短路求值),不会运算array[-1]
                arr[j + 1] = arr[j];        
                    arr[j+1] = temp; //被排序数放到正确的位置
        }
    }

    C++实现

    template<typename T> //整數或浮點數皆可使用,若要使用物件(class)時必須設定大於(>)的運算子功能
    void insertion_sort(T arr[], int len) {
        int i, j;
        T temp;
        for (i = 1; i < len; i++) {
            temp = arr[i];
            for (j = i - 1; j >= 0 && arr[j] > temp; j--)
                arr[j + 1] = arr[j];
            arr[i-1] = temp;
        }
    }

    4、复杂度分析

    (1)时间复杂度

     初始状态( n项)  正序  反序  无序(平均)
     第i趟比较次数  1  i  /
     总比较次数  n-1  n(n-1)/2  /
     第i趟移动次数  0  i  /
     总移动次数  0  n(n-1)/2  /
     时间复杂度  O(n)  O(n^2)  O(n^2)

    (2)空间复杂度

    在排序过程中仅需要一个元素的辅助空间,所以空间复杂度为为O(1)。

     5、改进

    (1)折半插入排序:因为使用插入排序得到的前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。

    (2)具体操作

    1、将待插入区域的首元素设置为a[low],末元素设置为a[high],则比较时将待插入元素与a[m],其中m=(low+high)/2相比较

    2、

    do{
        if(新元素<a[m])
            选择a[low]到a[m-1]为新的插入区域(即high=m-1)
        else
            选择a[m+1]到a[high]为新的插入区域(即low=m+1)
    }while(low>high)

    3、将此位置之后所有元素后移一位,并将新元素插入a[high+1]。

    (3)C实现

    #include <stdio.h>
    typedef int ElemType ;
    ElemType arr[]={0,9,8,7,6,5,4,3,2,1};
    ElemType n=10,i,j;
    ElemType low,high,mid;
    void BinSort(ElemType r[],ElemType n)
    {
        for(i=2;i<=n;i++)
        {
            r[0]=r[i];
            low=1; high=i-1;
            while (low<=high)
            {
                mid=(low+high)/2;
                if(r[0]<r[mid])
                    high=mid-1;
                else
                    low=mid+1;}
            for(j=i-1;j>=low;j--)
            {
                r[i]=r[j];
                i--;
            }
            r[low]=r[0];} }
    void put(ElemType r[],ElemType n)
    {
        for(j=1;j<n;j++)
            printf("%d	",r[j]);
        printf("
    ");
    }
    void main()
    {
        BinSort(arr,n);
        put(arr,n);
    }

    折半插入排序代码来源:http://baike.baidu.com/link?url=x12HcpirljXV_EWkGELhZEbwM1PBFMgZKENK6DspEH91gepF4ZkuHIdupjbBLqxJuYvTCDbBhupo41K81KZds_#4_3

    (4)复杂度分析

    时间复杂度:O(n^2) //折半查找只是减少了比较次数,但是元素的移动次数不变,所以折半插入排序算法的时间复杂度仍然为O(n^2)

    空间复杂度:O(1)

  • 相关阅读:
    Java main方法继承
    MySQL 事务
    数据库日志文件和内存刷新机制
    MySQL 存储过程
    MySQL 索引
    JVM锁优化
    JVM字节码执行引擎和动态绑定原理
    虚拟机类加载机制
    JVM内存分配与回收
    JVM垃圾收集器
  • 原文地址:https://www.cnblogs.com/crystalmoore/p/5930597.html
Copyright © 2020-2023  润新知