zoukankan      html  css  js  c++  java
  • 直接插入排序(python实现)

    这篇博文用来介绍直接插入排序

    直接插入排序基本思想:

    每次将一个待排序的记录插入到已经排好序的数据区中,直到全部插入完为止

    直接插入排序算法思路:

    在直接插入排序中,数据元素分为了有序区和无序区两个部分,在这里我们将列表左边部分作为有序区,列表右边部分作为无序区,有序区和无序区的大小是随着排序的进行而变化的。

    如最开始列表是无序的,所以有序区长度为1,无序区长度为列表长度-1,排序结束后,列表变为有序,则有序区长度为列表长度,无序区长度为0.

    具体步骤为:

    排序过程中每次从无序区中取出第一个元素,将它插入到有序区中的适当位置(即该元素放在此位置,有序区仍然有序),使之成为新的有序区,重复n-1次可完成排序过程。

    假设需要将列表从小到大排序

     想要将从无序区中取出的第一个元素temp插入到有序区中的适当位置,需要有一个循环遍历的过程,即从该元素位置处依次向前比较,会有两种情况:

      1,前面的元素waitsortlist[j-1]大于temp,则temp需要继续向前比较,同时大于temp的元素需要后移一位

      2,前面的元素waitsortlist[j-1]小于等于temp,则temp不需要继续比较了,因为temp大于有序区中最大的元素,有序区伸展一位,包含temp

    另外还需要考虑 j 的边界问题,因为会用到 j-1,所以 j 需要>=1防止越界,对于无序区某一个元素temp的直接插入代码如下:

            temp=waitsortlist[j]
            while j>=1:
                if temp<waitsortlist[j-1]:
                    waitsortlist[j]=waitsortlist[j-1]
                    j=j-1
                else:
                    break
            waitsortlist[j]=temp
    

     外层是一个列表的遍历,加上上面的代码为:

     

        i=0
        j=i+1
        while j<len(waitsortlist):
            temp=waitsortlist[j]
            while j>=1:
                if temp<waitsortlist[j-1]:
                    waitsortlist[j]=waitsortlist[j-1]
                    j=j-1
                else:
                    break
            waitsortlist[j]=temp
            i=i+1
            j=i+1
    

      可以看出,列表的第一个元素必为有序区,遍历的过程中不断扩大有序区的范围,对于列表某一个元素来说,就是将其插入在有序区中适当的位置,外层循环遍历结束后,有序区也扩充为列表长度,即排序结束。

    该算法的时间复杂度为O(n^2),因为有两层循环,时间开销比较大,空间复杂度为O(1),只是用了常数阶的空间来存储变量,用以直接插入排序

    全部代码为(实际上看了前面的相信你已经能写出来了:D

    '''
        直接插入排序
    '''
    def DirectInsertionSort(waitsortlist):
        i=0
        j=i+1
        while j<len(waitsortlist):
            temp=waitsortlist[j]
            while j>=1:
                if temp<waitsortlist[j-1]:
                    waitsortlist[j]=waitsortlist[j-1]
                    j=j-1
                else:
                    break
            waitsortlist[j]=temp
            i=i+1
            j=i+1
        return waitsortlist
    
    
    if __name__=='__main__':
        waitsortlist=[9,8,7,6,5,4,3,2,1,0]
        print(DirectInsertionSort(waitsortlist))
    

      运行结果为:

    直接插入排序 (带监视哨):

    哨兵的概念:一切为简化边界条件而引入的附加结点(元素)均可称为哨兵。

    在上面的代码我们可以看到有这一段:

    while j>=1:
    

      内循环每一次比较前都需要判断 j 是否越界,有没有不需要判断的办法呢?当然有,这就是哨兵的作用

    将上面的代码改为:

    def DirectInsertionSortEye(waitsortlist):
        i=1
        j=i+1
        while j<len(waitsortlist):
            temp=waitsortlist[j]
            waitsortlist[0]=temp
            while temp<waitsortlist[j-1]:
                waitsortlist[j]=waitsortlist[j-1]
                j=j-1
            waitsortlist[j]=temp
            i=i+1
            j=i+1
        return waitsortlist
    
    if __name__=='__main__':
        waitsortlist=[0,9,8,7,6,5,4,3,2,1,0]
        print(DirectInsertionSortEye(waitsortlist))
    

      输出的结果为:

     我们将waitsortlist[0]设置为哨兵,传入列表的时候,该位置也不能够放置有效元素,用列表一个元素的空间判断越界与否的比较时间。可以看出,一次循环少判断一次,n次循环少判断n次,当数据量较大时,很明显是优于不带监视哨的直接插入排序。

    带监视哨的直接插入排序思想也很简单,在原有基础上稍加修改即可,这里不再赘述。

  • 相关阅读:
    为什么 PCB 生产时推荐出 Gerber 给工厂?
    Fedora Redhat Centos 有什么区别和关系?
    【KiCad】 如何给元件给元件的管脚加上划线?
    MCU ADC 进入 PD 模式后出现错误的值?
    FastAdmin 生产环境升级注意
    EMC EMI 自行评估记录
    如何让你的 KiCad 在缩放时不眩晕?
    KiCad 5.1.0 正式版终于发布
    一次单片机 SFR 页引发的“事故”
    java基础之集合
  • 原文地址:https://www.cnblogs.com/Cl0ud/p/12942704.html
Copyright © 2011-2022 走看看