Python 算法之插入排序

640?wx_fmt=png

插入排序

插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前的扫描过程中,需要把已排序元素逐步向后挪位,为最新元素提供插入空间。

插入排序动态图

640?wx_fmt=gif

Insertion-sort

640?wx_fmt=gif

Insertion_sort_animation

实现代码

640?wx_fmt=png

insertion_sort

代码很短,只有 8 行。我们来每行代码来分析。

 
  

def insertion_sort(list):

第一行:定义插入排序函数,设置一个参数 list 用来接收数据。

 
  

def insertion_sort(list):
 n = len(list)

第二行:得到数据的长度

 
  

def insertion_sort(list):
 n = len(list)
 for i in range(1, n)

第三行:从 1 开始循环遍历整个数据,注意这里是从 1 开始,不是从 0 开始。因为第一个元素已经是有序的,所以不用在排序。

 
  

def insertion_sort(list):
 n = len(list)
 for i in range(1, n)
   for j in range(i, 0, -1)

第四行:开始从当前元素往后扫描数据

 
  

def insertion_sort(list):
 n = len(list)
 for i in range(1, n)
   for j in range(i, 0, -1)
     if list[j] < list[j - 1]

第五行:开始比较当前的元素是否比后面的元素小,因为插入排序就是从后往前开始比较元素。

 
  

def insertion_sort(list):
 n = len(list)
 for i in range(1, n)
   for j in range(i, 0, -1)
     if list[j] < list[j - 1]
       list[j], list[j - 1] = list[j], list[j - 1]

第六行:如果在往后比较的过程中,发现当前元素比前面的元素小,这进行交换。

 
  

def insertion_sort(list):
 n = len(list)
 for i in range(1, n)
   for j in range(i, 0, -1)
     if list[j] < list[j - 1]
       list[j], list[j - 1] = list[j], list[j - 1]
     else
       break

第七八行:否则退出当前循环,寻找下一个比较元素。

优化插入排序

上述代码并不是插入排序的最优的写法,我们可以在进一步优化。其实很多算法都有优化的地方,关键你要懂的原本的代码是什么导致了代码效率低,我们又可以如何优化。在我们上面写的代码中,其中的交换操作其实是很费操作步骤,因为一次交换,相当于 3 次复制,这还不包括内部的函数过程。所以我们可以根据这点进行优化,把原本交换操作,改成赋值语句。

640?wx_fmt=png

优化代码


优化后的代码如上,我们再来具体每行分析


 
  

def insertion_sort(list):
   n = len(list)
   for i in range(1, n):
       key = list[i]

前面的四行代码我就不在详细说明,我们从第五行代码开始说起。这行代码主要是用 key 来保存当前的值,用于后面赋值操作。

 
  

def insertion_sort(list):
   n = len(list)
   for i in range(1, n):
       key = list[i]
   j = i - 1

第六行:创建 j 变量值为 i - 1,代表当前元素的前一个元素下标。用于我们来比较。

 
  

def insertion_sort(list):
   n = len(list)
   for i in range(1, n):
       key = list[i]
   j = i - 1
   while j >= 0 & list[j] > key

第七行:这里我们使用 while 语句来循环,并且使用 & 在添加一个循环条件:当前的元素是否比原本的元素大。在直白点理解就是插入排序中,我们是要把当前元素与前一个元素进行比较。这里的当前元素就是 key,我们在最初有保存。前一个元素就是 list[j]。加了 & 以后,我们就有可能提前结束循环,提高算法效率。原先的写法,不管什么条件,都要一个个循环遍历一遍。

 
  

def insertion_sort(list):
   n = len(list)
   for i in range(1, n):
       key = list[i]
   j = i - 1
   while j >= 0 & list[j] > key
     list[j + 1] = list[j]

第八行:当满足上面的条件之后,我们就要把原本的当前元素进行赋值操作,赋值成较大的元素。这里和第九、第十行代码,用赋值操作替换掉了原先的交换操作,进一步提升算法效率。

 
  

def insertion_sort(list):
   n = len(list)
   for i in range(1, n):
       key = list[i]
   j = i - 1
   while j >= 0 & list[j] > key
     list[j + 1] = list[j]
     j -= 1

第九行:j - 1 往后继续比较。

 
  

def insertion_sort(list):
   n = len(list)
   for i in range(1, n):
       key = list[i]
   j = i - 1
   while j >= 0 & list[j] > key
     list[j + 1] = list[j]
     j -= 1
   list[j + 1] = key

第十行:当循环结束后,我们就找到了合适的插入位置,在把原本的值赋值过去。即 key 的值,保存到 list[j + 1]。

最后给大家留个疑问,代码最后 list[j + 1],为什么要 j + 1,不加 1 可以吗?欢迎在评论区写出你的看法。


推荐阅读: 





 知识与认知,财富与思维


640




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值