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级别。

  • 相关阅读:
    ElasticSearch工作原理
    prometheus监控es集群
    es索引调优
    ES中Refresh和Flush的区别
    网络服务器技术Apache与Nginx,IIS的不同
    shell里/dev/fd与/proc/self/fd的区别
    常用抓包工具
    Ubuntu Kubuntu Xubuntu Lubuntu Dubuntu Mythbuntu UbuntuBudgie区别
    Android的Looper.loop()消息循环机制
    申请读写sd卡权限shell
  • 原文地址:https://www.cnblogs.com/deng-tao/p/6445072.html
Copyright © 2011-2022 走看看