声明:引用请注明出处http://blog.csdn.net/finish_dream/article/details/70186029
引言
上一篇文章中介绍到插入排序中有三种具体排序方法,分别是:直接插入排序,二分法插入排序,希尔插入排序。上一篇《排序算法一:直接插入排序 》中已经介绍了直接插入排序,这篇文章将主要介绍二分法插入排序。
排序相关的基本概念
排序:将一组杂乱无章的数据按一定的规律顺次排列起来。
- 数据表(data list):它是待排序对象的有限集合。
- 排序码(key):通常对象有多个属性域,即多个数据成员组成,其中有一个属性域,可用来区分对象,作为排序依据。该域即为排序
码,每个数据表用哪个属性域作为排序码,要视具体的应用需要而定。
分类
- 内排序:指在排序期间数据对象全部存放在内存的排序;
- 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。
排序的分析
排序算法的稳定性
如果在对象序列中有两个对象r[i]和r[j] ,它们的排序码k[i]==k[j] 。如果排序前后,对象r[i]和r[j] 的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。
排序算法的评价
时间开销
- 排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。
- 算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算。
空间开销
算法执行时所需的附加存储。
二分法插入排序
基本思想
二分法插入排序是在插入第i个元素时,对前面的0~i-1元素进行折半,先跟他们中间的那个元素比,如果小,则对前半再进行折半,否则对后半进行折半,直到left>right,然后再把第i个元素前1位与目标位置之间的所有元素后移,再把第i个元素放在目标位置上。
C#代码
/// <summary>
/// 二分查找(一个数在一个序列中查找一个合适的位置)
/// </summary>
/// <param name="array">待查找数组</param>
/// <param name="x">元素</param>
/// <param name="low">下届</param>
/// <param name="high">上届</param>
/// <returns></returns>
private static int binarySearch(int[] array, int x, int low, int high)
{
if (high <= low) //出口1
return (x > array[low]) ? low + 1 : low;
//中间值
int middle = (high - low) / 2 + low;
if (x > array[middle])
return binarySearch(array, x, middle + 1, high);//在右半边
else if (x < array[middle])
return binarySearch(array, x, low, middle - 1); //在左半边
else
return middle;//出口2
}
/// <summary>
/// 二分法插入排序
/// </summary>
/// <param name="Array">待排序数组</param>
/// <param name="N">数组元素个数</param>
/// <returns></returns>
public static int[] BinarySort(int[] Array, int N)
{
int P, j, loc;
for (P = 1; P < N; P++)
{
j = P;
loc = binarySearch(Array, Array[P], 0, j - 1);
while (j > loc)
{
swap(ref Array[j - 1], ref Array[j]);
j--;
}
}
return Array;
}
二分法插入排序分析
- 二分搜索比顺序搜索查找快,所以二分插入排序就平均性能来说比直接插入排序要快。
- 它所需的排序码比较次数与待排序对象序列的初始排列无关,仅依赖于对象个数。在插入第i个对象时,需要经过log2i+1次排序码比较,才能确定它应插入的位置。 将n个对象用折半插入排序所进行的排序码比较次数比较次数(KCN):∑n−1(log2i+1)≈nlog2n
- 二分插入排序是一个稳定的排序方法。
- 当n较大时,总排序码比较次数比直接插入排序的最坏情况要好得多,但比其最好情况要差。
- 在对象的初始排列已经按排序码排好序或接近有序时,直接插入排序比折半插入排序执行的排序码比较次数要少。折半插入排序的对象移动次数与直接插入排序相同,依赖于对象的初始排列。
完整代码被我放在了Github上,感兴趣的可以下下来看一下https://github.com/Finish-Dream/DSAlgorithm