zoukankan      html  css  js  c++  java
  • 插入排序之直接插入排序算法

    1、什么是插入排序

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

    从第二个元素开始r[1],那么将他左边的元素作为一个已经有序的序列,将r[1]按从小到大的顺序插入到

    有序序列中的合适位置使之成为一个新的有序序列;接着将r[2]插入到左边的有序序列中,使之成为一个

    新的有序序列,依次类推,直道将所有的元素都遍历完了之后,那么整个数组就是一个从小到大的有序数组了。

    2、效果演示

            这是需要进行排序的序列

             对于第1个元素8来说,它本身就是有序的

             再来考虑第2个元素6,因为他比8小,交换一次位置

         

            再来考虑第3个元素2,因为他比8小,交换一次位置

            2又比左边的6小,交换一次位置

              再来考虑第4个元素,因为他比8小,交换一次位置

           3又比左边的6小,交换一次位置

           3比左边的2大,不需交换,前4个元素就已经排序完毕,后面的依次类推

    2、时间复杂度

    O(n^2)

    3、算法实现(基于C++)

     1 /* 直接插入排序算法实现 */
     2 template<typename T>
     3 void insertSort(T a[], int count)
     4 {
     5     /* 找到a[i]这个元素的合适插入位置,因为第一个元素前面没有元素,无法进行比较,所以从第二个元素开始 */
     6     for (int i = 1; i < count; i++) {
     7         for (int j = i; j > 0 && a[j - 1] > a[j]; j--) {  
     8             std::swap(a[j-1], a[j]);
     9         }
    10     }
    11 }

    4、直接插入算法的改进

    从上面的算法实现上可知,我们的直接插入排序算法上需要进行大量的两个元素交换的动作(swap函数),而两个元素交换在实现上是需要进行3次的赋值操作,所以会给整个过程造成大量的时间浪费,所以我们将对上面在算法的实现上进行一个改进,通过改进之后可以大大的缩短直接插入排序算法的所需要的时间。

    改进的思想: 其实就是通过直接的赋值操作代替大量的数组元素间的互换操作,具体的实现请看下面的演示

     首先还是从第2个元素开始排序,这次我们先将6这个元素拷贝出来一份,然

                                          后再与左边的8进行比较,6副本比8小,将8往右移动,再将6副本指针往左移动

      直接将6副本赋值给当前所指向的这个位置,此时前面2个元素排序完毕

           

       考虑第3个元素,还是先将其复制一份,2副本比左边的8小,将8往右移动,

                                           将2副本指针往左移动

       2副本又比左边的6小,将6往右边移动一次,将2副本指针往左移动

      直接将2副本赋值给当前所指向的这个位置

      前面3个元素排序完毕

      再来考虑第4个元素,首先还是先将其拷贝一份,3副本比左边的8小,直接

                                           将8往右移动,将3副本指针往左移动

      3副本又比左边的6小,将6往由移动,3副本指针往左移动

      此时3副本比左边的2大,这个位置合适,将3副本赋值给当前所指向的这个位置

      至此前面的4个元素排序完毕,依次类推

    由此可以知道经过上面的方法之后,减少了两个元素之间的交换操作,大大缩短了时间。

    算法的实现如下:

     1 /*********************************** 直接插入排序算法实现 ********************************/
     2 template<typename T>
     3 void insertSort (T a[], int count)
     4 {
     5     /* 找到a[i]这个元素的合适插入位置,因为第一个元素前面没有元素,无法进行比较,所以从第二个元素开始 */
     6     for (int i = 1; i < count; i++) {
     7         int j;
     8         T copy = a[i];           // 将需要插入到左边有序序列的元素拷贝出来作为一个副本
     9         for (j = i; j > 0 && a[j - 1] > copy; j--) { 
    10             a[j] = a[j - 1];     // 如果条件满足,直接前一个元素赋值给后面的元素
    11         }
    12         a[j] = copy;             //  找到该元素的合适位置之后直接赋值即可
    13     }
    14 }
    15 /**********************************************************************************************/

    我们将一系列的元素之间的交换变成了赋值操作,大大的缩短了排序所需要的时间,可以大大提高程序运行的效率。

    5、总结

    (1)插入排序的时间复杂度是O(n^2)级别

    (2)插入排序的内层循环是可以提前终止的,因为只要找到了合适的位置,将元素插入到该位置后就可以终止本次循环了。

    (3)如果需要进行排序的数组序列本来就是一个非常有序的状态,那么插入排序执行起来的效果将比选择排序快上很多,因为插入排序的内层循环将大大的减少时间,而选择排序内层循环每一次都会循环到底,所以在时间上将远远超过插入排序,所以当需要排序的数组序列本来就是一个非常有序的状态,那么内层的循环基本上不用做了,这样会大大提升效率。当需要进行排序的序列几乎接近于有序时,插入排序的时间复杂度将会变为n级别。

  • 相关阅读:
    PHP实现无限极分类
    html2canvas生成并下载图片
    一次线上问题引发的过程回顾和思考,以更换两台服务器结束
    Intellij IDEA启动项目报Command line is too long. Shorten command line for XXXApplication or also for
    mq 消费消息 与发送消息传参问题
    idea 创建不了 java 文件
    Java switch 中如何使用枚举?
    Collections排序
    在idea 设置 git 的用户名
    mongodb添加字段和创建自增主键
  • 原文地址:https://www.cnblogs.com/deng-tao/p/6445072.html
Copyright © 2011-2022 走看看