插入排序(Insertion Sort)是一种简单直观的排序算法。
通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插入排序在实现上,在从后向前的扫描过程中,需要把已排序元素逐步向后挪位,为最新元素提供插入空间。
插入排序动图:
(用MD写的,插入的动图貌似是不会动了。。。。)
从第二位开始,依次和前面的数进行比较,第一位默认已经是有序的了;
第三位和前两位依次比较,第四位和前三位依次比较;
前面的元素均为有序,后面为无序;
即:
先将前两个排序
再将前三个排序
前四个
…
一直到最末尾
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-1],list[j]
else:
break
return 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):
if list[j] < list[j-1]
list[j],list[j-1] = list[j-1],list[j]
从当前元素开始依次往前扫描
判断与前一位相比大小
上面的代码中,交换操作很费操作步骤,因为一次交换,相当于 3 次复制,这还不包括内部的函数过程。所以我们可以根据这点进行优化,把原本交换操作,改成赋值语句。
def insertion_sort(list):
n = len(list)
for i in range(1, n):
key = list[i]
j = i - 1
while j >= 0 and list[j] > key:
list[j+1] = list[j]
j -= 1
list[j+1] = key
return list
list1 = [5,6,2,7,9,0,1,3,8,4]
print("原列表:%s" %list1)
insertion_sort(list1)
print("排序后列表:%s" %list1)
>> 原列表:[5, 6, 2, 7, 9, 0, 1, 3, 8, 4]
排序后列表:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
优化后代码解析:
def insertion_sort(list):
n = len(list)
for i in range(1, n):
key = list[i]
j = i - 1
首先,遍历列表每一位,然后用 key 保存当前位置的值; j 表示前一位;
def insertion_sort(list):
n = len(list)
for i in range(1, n):
key = list[i]
j = i - 1
while j >= 0 and list[j] > key:
然后,使用 while 条件循环,判断前一位的元素是否比当前位的大,并且前一位的下标 >= 0(即最小到第一位)
这样就可以有条件的进行循环,而不像原来的写法那样一个个循环遍历。
def insertion_sort(list):
n = len(list)
for i in range(1, n):
key = list[i]
j = i - 1
while j >= 0 and list[j] > key:
list[j+1] = list[j]
j -= 1
list[j+1] = key
return list
符合条件后,就可以把原来的元素位进行赋值操作,赋值成较大的元素;然后依次将较大的元素赋值给相比较的两位中的后面一位。直至比较到第一位或比较到某位元素小于当前元素的值。将保存起来的该位的值插入即可。
例:list = [1,4,5,3]
- 1循环 i 到第四位了 (i = 3)
- key保存 list[3] 的值,即 key = 3
- 然后将 list[2] 与 key = 3 比较,5>3,则将5的值赋给后面那位,即[1,4,5,5]
- 再将 list[1] 与 key = 3 比较 ,4>3,则将4的值赋给后面那位,即[1,4,4,5]
- 再将 list[0] 与 key = 3 比较 ,1<3,不符合循环条件
- 于是执行后面的语句,将 key = 3 值赋给 list[0+1] 即list[1],即[1,3,4,5]
补个range()函数小知识点:
生成顺序的:
for i in range(1,10,1)
print(i)
>> 1,2,3,4,5,6,7,8,9
生成倒序的:
for i in range(10,0,-1)
print(i)
>> 10,9,8,7,6,5,4,3,2,1
因为 顾头不顾尾 ,所以生成的数减到 1 即停止了,不包括 0 。
优化后的代码,while 条件使用了两个条件与的判断
最初使用了 & 运算符,结果导致始终进不了循环,然后改为 and 即正常
运算符 | 名称 | 说明 | 例子 |
---|---|---|---|
& | 按位与 | 数的按位与 | 5&3 得1 |
and | 布尔“与” | 如果x为False,x and y返回False,否则它返回y的计算值 | x = False; y = True; x and y,由于x是False,返回False。在这里,Python不会计算y,因为它知道这个表达式的值肯定是False(因为x是False)。这个现象称为短路计算 |