参考:
百度百科:折半插入排序
百度百科:二分法插入排序
折半插入排序(binary insert sort)
工作原理
对插入排序算法的改进,针对已排序序列,利用 二分法 进行数据查找,将待排序数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据。
算法思想
设待排序序列大小为 n
,共遍历 n-1
次,i
表示当前遍历的次数,也表示已排序序列的终止位置和待排序序列的起始位置。设置已排序序列开始和末尾下标为 low
和 high
,其中中间位置数据的下标为 m = (low+high)/2
。将待排序数据和中间位置数据进行比较,如果中间位置数据 小于等于(或者大于等于) 待排序数据,则设置 low = m+1
;否则 high = m-1
,然后继续计算中间下标 m
,进行比较,直到满足条件 low > high
为止,将待排序数据插入到 hight+1
的位置
Python 算法实现
# -*- coding: utf-8 -*-
"""
二分插入排序,又称折半插入排序
"""
import random
def create_data(leng, min, max):
"""
创建待排序序列
:param leng: 序列长度
:param min: 最小值
:param max: 最大值
:return: 列表
"""
li = range(min, max)
return random.sample(li, leng)
def binary_insert_sort(li, reverse=False):
"""
二分插入排序实现
:param li: 待排序列表
:param reverse: 是否从大到小排序,默认为False
:return: 已排序列表
"""
for i in xrange(1, len(li)):
low = 0
high = i - 1
while low <= high:
m = (low + high) / 2
if li[m] <= li[i]:
if reverse:
high = m - 1
else:
low = m + 1
else:
if reverse:
low = m + 1
else:
high = m - 1
li.insert(high + 1, li[i])
del li[i + 1]
return li
if __name__ == '__main__':
da = create_data(10, 30, 60)
print da
binary_insert_sort(da, True)
print da
性能分析
稳定性
折半插入排序是稳定排序算法
折半插入排序是对插入排序算法的改进,重点变化在于待排序数据的比较过程。
但是,在实际编程中,同样有可能使折半插入排序成为 不稳定的排序算法,下面介绍不稳定的排序算法过程
假设有如下待排序序列:(3,0),(2,1),(3,2)
,实现从小到大的排序
- 第一次排序,已排序序列为
(3,0)
,所以low = high = 0 -> m = 0
,待排序数据(2,1)
比中间位置数据(3,0)
小,所以high = m-1 = -1
,满足low > high
的条件,结束排序,将(2,1)
插入到high+1 = 0
的位置
得到结果:(2,1),(3,0),(3,2)
- 第二次排序,已排序序列为
(2,1),(3,0)
,所以low = 0, high = 1, m = 0
,待排序数据为(3,2)
第一次比较,(2,1)
小于 (3,2)
,所以 low = m+1 = 1, m = (low + high) / 2 = 1
第二次比较,(3,0)
大于等于 (3,2)
,所以 high = m-1 = 0
,所以 low > high
,将 (3,2)
插入到 high+1 = 1
的位置上
得到结果:(2,1),(3,2),(3,0)
,是不稳定的排序结果
所以,在比较时,当中间数据 大于等于(或者小于等于)待排序数据时,选择右边已排序序列继续操作,才能保证是稳定的
时间复杂度
折半插入排序改变了插入排序算法的比较次数,未改变其待排序数据移动次数
最好情况下,插入的位置,刚好是二分位置,时间复杂度为 O(nlogn)
最坏情况下,时间复杂度为 O(n^2)
平均时间复杂度为 O(n^2)
空间复杂度
空间复杂度为 O(1)