插入排序
介绍
插入排序将待排序数组分成两部分:已排序部分和待插入部分。将带插入部分逐个插入到已排序序列中。它是in-place的,时间复杂度O(n2)
,空间复杂度O(1)
。
循环不变式:在将第i
个元素插入之前,array[0~i-1]
是已经有序的。
实现
输入: 待排序数组array
。可以随机访问它的每个元素,和它的长度。
输出: 按非下降顺序排序的数组array
。
V1
最直观的,在插入第i
个元素时,称它为key
,依次比较前面的元素直到遇到不比key
大的元素为止,这样就找到了插入点。为了插入key
,需要将插入点到i-1
这些位置的元素后移一位,这里在寻找插入点的时候就已经做了移动。
def insertion_sort_v1(array):
print("insertion_sort_v1: ", end = '')
length = len(array)
for i in range(1, length):
key = array[i]
for j in range(i-1, -1, -1):
if array[j] <= key:
array[j+1] = key
break
else:
array[j+1] = array[j]
else:
array[0] = key
V2
前面的方法逻辑上没有考虑第i
个元素是否需要插入。只有在当第i
个元素比第i-1
个元素小时,才需要插入,否则直接处理下一个循环。V2其实跟V1没什么差别。
def insertion_sort_v2(array):
print("insertion_sort_v2: ", end = '')
length = len(array)
for i in range(1, length):
if array[i] < array[i-1]:
key = array[i]
array[i] = array[i-1]
for j in range(i-2, -1, -1):
if array[j] <= key:
array[j+1] = key
break
else:
array[j+1] = array[j]
else:
array[0] = key
V3
在寻找插入点的时候,考虑到前面一段是已排序数组,可以直接使用二分查找,这样查找的速度会变快。但是数据移动的复杂度依旧是O(n)
,整体复杂度不变。
def insertion_sort_v3(array):
print("insertion_sort_v3: ", end = '')
length = len(array)
for i in range(1, length):
if array[i] < array[i-1]:
key = array[i]
low = 0
high = i - 2
while(low <= high):
mid = (low + high)//2
if array[mid] <= key and array[mid+1] > key:
break
elif array[mid] <= key:
low = mid + 1
else:
high = mid - 1
else:
mid = low -1
for j in range(i-1, mid, -1):
array[j+1] = array[j]
array[mid+1] = key