基本思想
考虑到直接插入排序的基本思想就是每次将无序区里的元素插入到有序区,那么可以利用表的有序性在有序区中使用折半查找查找插入位置。
对于递增有序表,我们查找插入位置就是第一个关键字大于插入元素关键字的元素位置,因此折半插入就需要查找有序区中第一个关键字大于要插入元素关键字的元素位置。
综合以上分析 ,可以采用与直接插入排序相同的方法,扫描无序曲,依次比较元素,然后元素插入的位置使用折半查找,然后移动插入位置后的有序区元素,最后进行元素插入。
实现
void bin_sort(RecType R[], int n)
{
int i, j, low, mid, high;
RecType tmp;
for (i=1; i<n; i++)
if (R[i].key < R[i-1].key)
{
tmp = R[i];
low = 0;
high = i-1;
while (low <= high)
{
mid = (low + high) / 2;
if (tmp.key < R[mid].key)
high = mid - 1;
else
low = mid + 1;
}
for (j=i-1; j>=high+1; j--)
R[j+1] = R[j];
R[high+1] = tmp;
}
}
算法分析
时间复杂度
平均比较次数与折半查找的判定树有关,因此R[i]插入到有序区的平均比较次数为
l
o
g
2
(
i
+
1
)
−
1
log_2{(i+1)-1}
log2(i+1)−1
平均移动次数与直接插入排序一样,都为
i
2
+
2
\frac i2 + 2
2i+2
综上,平均时间复杂度为
∑
1
n
−
1
(
l
o
g
2
(
i
+
1
)
−
1
+
i
2
+
2
)
=
O
(
n
2
)
\sum_1^{n-1}(log_2(i+1)-1 + \frac i2 + 2) = O(n^2)
1∑n−1(log2(i+1)−1+2i+2)=O(n2)
空间复杂度
很显然,折半插入排序是一个原地工作算法,其所需临时空间相对于问题规模来说是常数,所以空间复杂度为
O
(
1
)
O(1)
O(1)
稳定性
折半插入排序将元素插入到有序区中第一个关键字大于它的元素的位置,与相同关键字元素的相对位置不改变,所以是稳定的排序算法
适用情况
相对于直接插入排序,平均时间复杂度没有改善,而在查找插入位置的比较次数方面的效率得到了提高。折半插入排序适用于
数据量较小,且基本有序的情况