**插入排序和希尔排序是两种很像的排序,因为希尔排序是在插入排序的基础上进行,并且最后的间隔设置为1时,也就是插入排序 **
一、插入排序
插入排序(英语:Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
我们可以这样来理解,对于给定的一个列表,我们假设它分为两部分,前面的一部分是已经排好序的,后面的一部分是无序的。每次拿出无序列表中的第一个数去和有序列表中的最后一个数进行比较,如果比它大,就跟他交换位置,否则结束比较(因为前面的是有序数列,比最后一个大,意味着比前面的都要大);接着将它和有序列表中的倒数第二个数进行比较……以此类推。
下面我们用代码来实现:
def insert_sort(alist):
"""
我们先考虑第一次循环的情况
i = 1 # 第一次应该是第二个数和第一个数进行比较,即索引为1
if alist[1] < alist[0]:
alist[1],alist[0] = alist[0],alist[1]
我们再考虑第二次循环的情况
i=2
if alist[2] < alist[1]:
alist[2],alist[1] = alist[1],alist[2]
if alist[1] < alist[0]
alist[1],alist[0] = alist[0],alist[1]
"""
n = len(alist) # 定义所排序列表的长度
for j in range(1,n):
for i in range(j,0,-1):
if alist[i] < alist[i-1]:
alist[i], alist[i-1] = alist[i-1], alist[i]
如果此种方法难以理解的话,可以这样来看:
def insert_sort2(alist):
n = len(alist)
for j in range(1,n): # 即j的取值为 1—n-1
count = j
"""
第一次:alist[1]和alist[0]比较
第二次:alist[2]和alist[1]、alist[1]和alist[0]比较
第三次:alist[3]和alist[2]、alist[2]和alist[1]、alist[1]和alist[0]比较
………………
"""
while count > 0:
if alist[count] < alist[count-1]:
alist[count],alist[count - 1] = alist[count - 1],alist[count]
count -= 1
else:
break
if __name__ == "__main__":
li = [45,25,12,86,42,14]
insert_sort2(li)
print(li)
**结果如下*
[12, 14, 25, 42, 45, 86]
最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
最坏时间复杂度:O(n^2)
稳定性:稳定
二、希尔排序
希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
假设有这样一个数组,我们设置他们的gap为4:
13 14 94 33 82 25 59 94 65 23 45
那么我们可以得到下面的分割:
13 25 45
14 59
94 94
33 65
82 23
然后每一行就行插入排序的操作,之后再进行下一轮的排序,重新设置gap的值。最后令gap的
值为1,也就变成了插入排序
下面我们用代码实现:
def shell_sort(alist):
n = len(alist) #定义alist的长度
gap = n//2 # 定义gap的初始长度(“最后的最优时间复杂度和它有关,但这是一个数学问题,我们在这里不予考虑”)
while gap > 0:
for i in range(gap,n):
#内部即插入排序的操作,不过是将步长由1设置为gap
while i >0:
if alist[i] < alist[i-gap]:
alist[i],alist[i-gap] = alist[i-gap],alist[i]
i -= gap
else:
break
gap = gap//2
if __name__ == "__main__":
li = [45,25,12,86,42,14]
shell_sort(li)
print(li)
**运行结果如下:**
[12, 14, 25, 42, 45, 86]
最优时间复杂度:根据步长序列的不同而不同
最坏时间复杂度:O(n^2)
稳定想:不稳定
假定一个数组为[12,46,x23,23,54],设置步长为2.那么第一次排序的时候,数组变为[12,23,x23,46,54]