插入排序
插入排序的基本方法:每步将待排序的元素,按其排序码的大小插入到前面已经拍好的一组元素的适当位置上去,直到元素全部插入位置。
可以选择不同的方法,在已经排好序的有序数据表在寻找插入位置,依据查找方法的不同,有多种插入排序的方法。下面是常用的三种方法:1,直接排序;2,折半排序;3,希尔排序。
1,直接插入排序
定义:插入排序(Insertion Sort)算法一般讲数据分成两组,分别是有序组和无序组,并将数据的第一个元素默认为有序组,依次将无序组的元素依次按照降序或者是升序的方式插入到有序组中。
图例分析
Python 源码:
def InsertSort(A):
''' 这是一个直接插入排序算法'''
if not A or len(A)==1: # 如果输入的列表为空或者程度为1,则返回自身
return A
# 第一个元素默认为有序组,后面的(i+1)开始往后的元素都为无序组,并且依次与前面有序组的元素
# 进行比较排序
for j in range(1,len(A)):
i = j
while i > 0:
if A[i] < A[i-1]:
A[i],A[i-1] = A[i-1],A[i]
i -= 1
else:
break
return A
if __name__ == "__main__":
A = [6, 2, 4, 1, 3, 5, 2]
print(InsertSort(A)) # 结果是:[1,2,2,3,4,5,6]
2,折半排序
定义:折半插入排序(binary insertion sort)是对插入排序算法的一种改进,由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。 在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素大,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。
稳定性及复杂度
折半插入排序算法是一种稳定的排序算法,比直接插入算法明显减少了关键字之间比较的次数,因此速度比直接插入排序算法快,但记录移动的次数没有变,所以折半插入排序算法的时间复杂度仍然为O(n^2),与直接插入排序算法相同。附加空间O(1)。
Python代码:
def BinInsetSort(s):
''' 这是一个折半排序算法'''
for i in range(1,len(s)):
if s[i] < s[i-1]:
small = s[i]
low =0
high = i-1
while low <= high:
mid = (low+high)//2
if small < s[mid]:
high = mid - 1
else:
low = mid+1
for j in range(i-1,high-1,-1):
s[j+1] = s[j]
s[high+1] = small
s = [2,1,4,5,0,3,4,0]
BinInsetSort(s)
print(s) # 结果为:[0, 0, 1, 2, 3, 4, 4, 5]
3,希尔插入排序
定义:希尔排序是一种改进版的插入算法,也称缩小增量排序。按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减少到1时,算法终止。
Python源码:
def shellSort(A):
''' 这是一个希尔排序'''
if not A or len(A)==1:
return A
grap = len(A)//2
while grap > 0:
for i in range(grap,len(A)): # 跟每一个grap组的最后一个元素
first = i
while first > 0: # 跟同一个grap组之前的元素进行比较,当不存在时跳出循环
if A[first] < A[first-grap]:
A[first],A[first-grap] = A[first-grap],A[first]
first -= grap # 找到前一个元素,继续比较
else:
break
grap //= 2 # 缩小增量
return A
A=[3,2,4,1,7,5,0,8]
s = shellSort(A)
print(s) # 结果为: [0, 1, 2, 3, 4, 5, 7, 8]