上一篇文章中直接插入排序算法简单,且容易实现,当待排序的长度n很小时,是一种很好的排序方法,尤其当原始序列接近有序时,效率更好。如果待排序的长度n很大,则不适宜采用直接排序。这时我们可以考虑对其做些改进,我们可以从减少比较和移动的次数入手,因此可以采用折半插入排序,其思想类似于折半查找。由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。
折半插入排序的算法思想
把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中
取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。
把a[i]插入到a[0],a[1],...,a[i-1]有序表之中的具体实施过程为:
在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为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)。
算法实现代码:
void binary_insertion_sort(int *a,int n)
{
int i;
//从第1个元素开始循环执行插入排序
for(i=1;i<n;i++)
{
int low=0;
int high=i-1;
int temp=a[i]; //temp标记为未排序元素
//循环至要插入的两个点之间 即查找插入位置
while (low<=high)
{
int mid=(low+high)/2;
if (temp<a[mid])
high=mid-1;
else
low=mid+1;
}
//循环结束后low=high+1,并且low位置即为temp要插入的位置
//从low到i的元素依次后移一位
int j;
for (j=i;j>low;j--)
{
a[j]=a[j-1];
}
//将temp插入到low位置处
a[low]=temp;
}
}
参考:
http://www.cnblogs.com/java-class/archive/2013/06/01/3112461.html
http://blog.csdn.net/ns_code/article/details/20043459