插入排序
插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前的扫描过程中,需要把已排序元素逐步向后挪位,为最新元素提供插入空间。
插入排序动态图
Insertion-sort
Insertion_sort_animation
实现代码
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 次复制,这还不包括内部的函数过程。所以我们可以根据这点进行优化,把原本交换操作,改成赋值语句。
优化代码
优化后的代码如上,我们再来具体每行分析
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 可以吗?欢迎在评论区写出你的看法。
推荐阅读:
知识与认知,财富与思维