数据结构(python) —— 【07排序: 插入排序】

插入排序

1. 前言

    前几天在打高教杯数学建模国赛,然后最近又在缓解数学建模通宵遗留下来后遗症,所以一直没有更新。
    先简单说说这次2020高教杯数学建模国赛的感受吧。我们选的是B题——穿越沙漠。一道分析+代码的综合性路径规划题,其实我们刚开始走入了一个误区,以为这道题目应该是算法比重偏大,所以一开始就在那里写智能性算法,可是我写了一晚之后,发现算法过于复杂,所以第二天早上就有点崩溃了,甚至产生了换题的想法,好在队长坚持做这道题,最后没有换题。后来我看到网上一些人对于这道题目的评价,说了一些思路比如动态规划啥的,就说很简单,但我觉得那是因为他们没有深入去做这道题目,当他们真的去写算法了,就会发现里面的条件多得吓人,数据也不少…最后我们以三天吃了三顿饭,睡了8个小时的代价,终于把题目做好,交了上去,但是现在看看,其实我们只做了题目要求的,而没有扩展,所以成绩可能不会理想。
    好了,进入正题吧。今天要介绍的排序算法——插入排序是Low B三人组排序算法中的最后一个排序算法了。

2. 算法思想

    和前面两个排序方法一样,我们同样将列表或者数组分为有序区和无序区。主要想法: 按照顺序,每次取出一个数,如果左边有值,就和左边的数从右到左依次比较,如果比当前数大,就将该数往右移一位,知道找到一位比手上数小的,放在该数的右边。说得比较抽象,举个例子就好理解了。

3. 例子

用插入排序将列表[3, 2, 4, 1, 5, 7, 9, 6, 8]进行排序:

  1. 第一步: 取出列表第二个数即索引index=1的数2,将这个数和左边的数3比较,如果比3大,就还是放在当前位置中,要是比3小,就把3往右移,然后把2放入3的位置,即index=0的位置。所以第一步结束后,得到的结果为[2, 3, 4, 1, 5, 7, 9, 6, 8],即现在前两个位置即index=0、1都属于有序区。
  2. 第二步: 第一步取的是索引为index=1的数,那就按顺序继续往下取,即取index=2的数或者可以理解为第一步已经出现了有序区index=0、1,现在我们就从无序区中取数,去和有序区的数进行比较。所以这一步取出无序区第一个数4,将4和左边的数即有序区的数依次比较,先和3比较,发现大于3就直接不需要动了,直接把4放在原本的位置。所以这一步得到的是[2, 3, 4, 1, 5, 7, 9, 6, 8],此时有序区为[2, 3, 4],无序区为[1, 5, 7, 9, 6, 8]
  3. 第三步: 继续从无序区中取数,所以取的数为1,将1和有序区的数进行比较,1先和4比较,1<4,所以将4右移;将13比较,1<3,所以3也右移;将12比较,1<2,所以2也右移,所以最后只剩下最左边的位置即index=0的位置没有值了,此时,就把1放入。该步得到的结果为: [1, 2, 3, 4, 5, 7, 9, 6, 8]。有序区为[1, 2, 3, 4, 5],无序区为[7, 9, 6, 8].
  4. 第四步: 从无序区中取出775比较,5<7,所以7保持原位不动。得到结果为: [1, 2, 3, 4, 5, 7, 9, 6, 8],有序区为: [1, 2, 3, 4, 5, 7],无序区为: [9, 6, 8]
  5. 第五步: 从无序区中取出数9,9和7比较,7<9,所以9不动。得到结果为: [1, 2, 3, 4, 5, 7, 9, 6, 8],有序区为: [1, 2, 3, 4, 5, 7, 9],无序区为: [6, 8]
  6. 第六步: 从无序区中取出6和9比较,9>6,则将9右移一位;继续将6和7进行比较,7>6,将7右移一位;将65进行比较,5<6,则此时把6放在5的右边,得到的结果为: [1, 2, 3, 4, 5, 6, 7, 9, 8],有序区为: [1, 2, 3, 4, 5, 6, 7, 9],无序区为: [8]
  7. 第7步: 从无序区中取出89进行比较,9>8,则9右移一位;再将87比较,8>7,则8就放在7的右边即可,得到的结果为: [1, 2, 3, 4, 5, 6, 7, 8, 9],此时无序区已经没有值了,证明排序完成!

这里解释一下,为什么第一步是从第二个数即index=1的数开始取的。因为我们每次都是把取出的数和其左边的数进行比较,如果取index=0的数,那么该数的左边没有数,就不需要进行比较,所以我们的算法就直接省略了这一步,直接从index=1开始了。

4. 代码

接着来看看代码吧:

def insert_sort(li):
    for i in range(1, len(li)):   # i 表示取出的数的下标
        temp = li[i]
        j = i - 1   # j 指的是有序区中我们要比较的数的下标
        while j >= 0 and li[j] > temp:  # j>0保证了左边有值,li[j] > temp是要将左边的数右移的条件,即如果左边的数>取出的数,就将左边的数右移
            li[j+1] = li[j]   # 左边的数右移
            j -= 1   # 从右往左,继续在无序区中找数
        li[j + 1] = temp  # 直到所有的数都往右移了,只剩下最左边即Index=0的位置没数了或者当左边的数<取出的数了,就将取出的数放在该位置
        print(li)

使用一下:

def insert_sort(li):
    for i in range(1, len(li)):   # i 表示摸到的牌的下标
        temp = li[i]
        j = i - 1   # j 指的是手里的牌的下标
        while j >= 0 and li[j] > temp:
            li[j+1] = li[j]   # 摸到的牌左边的牌右移
            j -= 1
        li[j + 1] = temp
        print(li)

li = [3, 2, 4, 1, 5, 7, 9, 6, 8]
insert_sort(li)

结果为:

[2, 3, 4, 1, 5, 7, 9, 6, 8]
[2, 3, 4, 1, 5, 7, 9, 6, 8]
[1, 2, 3, 4, 5, 7, 9, 6, 8]
[1, 2, 3, 4, 5, 7, 9, 6, 8]
[1, 2, 3, 4, 5, 7, 9, 6, 8]
[1, 2, 3, 4, 5, 7, 9, 6, 8]
[1, 2, 3, 4, 5, 6, 7, 9, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值