目录
此次博客中的直接插入排序(及二分优化版直接插入排序)、希尔排序都是属于插入排序。博客代码是博主想复习下排序算法然后手打的,已经过调试。若还有错误请指出!
一、直接插入排序
算法思想:
假设有一组无序序列 R0, R1, ... , RN-1。
(1) 我们先将这个序列中下标为 0 的元素视为元素个数为 1 的有序序列。
(2) 然后,我们要依次把 R1, R2, ... , RN-1 插入到这个有序序列中。所以,我们需要一个外部循环,从下标 1 扫描到 N-1 。
(3) 接下来描述插入过程。假设这是要将 Ri 插入到前面有序的序列中。由前面所述,我们可知,插入Ri时,前 i-1 个数肯定已经是有序了。
所以我们需要将Ri 和R0 ~ Ri-1 进行比较,确定要插入的合适位置。这就需要一个内部循环,我们一般是从后往前比较,即从下标 i-1 开始向 0 进行扫描
当数据正序时,执行效率最好,每次插入都不用移动前面的元素,时间复杂度为O(N)。
当数据反序时,执行效率最差,每次插入都要前面的元素后移,时间复杂度为O(N^2)。
所以,数据越接近正序,直接插入排序的算法性能越好
平均 最坏 最好 空间 稳定性 复杂性
O(n²) O(n²) O(n) O(1) 稳定 简单
算法稳定性
直接插入排序的过程中,不需要改变相等数值元素的位置,所以它是稳定的算法。
Python代码
# 直接插入排序
def insert_sort(input_list):
if len(input_list) <= 1:
return input_list
for i in range(len(input_list)):
j = i - 1
while j >= 0 and input_list[j] > input_list[j+1]:
input_list[j],input_list[j+1] = input_list[j+1],input_list[j]
j -= 1
return input_list
二、二分查找优化直接插入排序
因为在一个有序序列中查找一个插入位置,以保证有序序列的序列不变,所以可以使用二分查找,减少元素比较次数提高效率。
Python代码
- 二分查找递归版
# 递归二分查找 有指针
def binary_search2(input_list, num, left, right):
if left > right:
return left if left < len(input_list) else -1 # 若所找的数大于数组所有数则会返回-1,即放在最后,其他情况返回left即可
middle = (left + right) // 2
if num > input_list[middle]:
left = middle + 1
elif num < input_list[middle]:
right = middle - 1
else:
return middle
return binary_search2(input_list,num,left, right)
- 二分查找非递归版
# 无递归二分查找 有指针
def binary_search1(input_list,num):
'''
:param num:
:param input_list: 有序列表
:return: 所找数字的索引
'''
# 每次二分 直到最后一次才找到 就会有 2^k = n / 2 得到 k = long2n + 1
# 如果找不存在数组里的要return left,否则返回-1
# 二叉树查找的思想是二分查找,查找的次数(效率)取决于二叉树的高度。
left = 0
right = len(input_list) - 1
while left <= right:
middle = (left + right) // 2
if num == input_list[middle]:
return middle
elif num > input_list[middle]:
left = middle + 1
else:
right = middle - 1
return left if left < len(input_list) else -1 # 若所找的数大于数组所有数则会返回-1,即放在最后,其他情况返回left即可
- 二分查找直接插入排序
# 直接排序优化:利用二分搜索查找索引加快速度
def binary_insert_sort(input_list):
if len(input_list) <= 1:
return input_list
for i in range(1,len(input_list)):
j = i - 1
search_index = binary_search1(input_list[:i+1],input_list[i])
if search_index != -1:
while j >= search_index:
input_list[j],input_list[j+1] = input_list[j+1],input_list[j]
j -= 1
else: # 若是-1,说明input_list[i]比它之前的数都大,所以不用改变位置
break
return input_list
三、希尔排序
算法思想:
希尔排序:缩小增量排序
增量:等于组数,等于每组元素相隔距离
步长序列的不同,会导致最坏的时间复杂度情况的不同。
以N/2为步长的最坏时间复杂度为N^2。用这样步长序列的希尔排序比插入排序要快,甚至在小数组中比快速排序和堆排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。
直接插入排序更适合于原始记录基本有序的集合。
希尔排序的比较次数和移动次数都要比直接插入排序少,当N越大时,效果越明显。
直接插入排序也适用于链式存储结构;希尔排序不适用于链式结构。
平均 最坏 最好 空间 稳定性 复杂性
O(nlogn) O(n²) O(n) O(1) 不稳定 较复杂
算法稳定性
希尔排序中相等数据可能会交换位置,所以希尔排序是不稳定的算法。
Python代码
def shell_sort(input_list):
if len(input_list) <= 1:
return input_list
gap = len(input_list) // 2
while gap >= 1:
for i in range(gap,len(input_list)):
j = i -gap
while j >= 0 and input_list[j] > input_list[j+gap]:
input_list[j],input_list[j+gap] = input_list[j+gap],input_list[j]
j -= gap
gap //= 2
return input_list