声明:引用请注明出处http://blog.csdn.net/finish_dream/article/details/70175039
引言
接下来将对排序算法做一个全面的梳理,从最简单的“冒泡”到高效的堆排序等。
排序相关的基本概念
排序:将一组杂乱无章的数据按一定的规律顺次排列起来。
- 数据表(data list):它是待排序对象的有限集合。
- 排序码(key):通常对象有多个属性域,即多个数据成员组成,其中有一个属性域,可用来区分对象,作为排序依据。该域即为排序
码,每个数据表用哪个属性域作为排序码,要视具体的应用需要而定。
分类
- 内排序:指在排序期间数据对象全部存放在内存的排序;
- 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。
排序的分析
排序算法的稳定性
如果在对象序列中有两个对象r[i]和r[j] ,它们的排序码k[i]==k[j] 。如果排序前后,对象r[i]和r[j] 的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。
排序算法的评价
时间开销
- 排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。
- 算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算。
空间开销
算法执行时所需的附加存储。
插入排序(Insert Sorting)
基本思想
每步将一个待排序的对象,按其排序码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。
分类
根据寻找插入位置方法分为
- 直接插入排序
- 折半插入排序
- 希尔插入排序
直接插入排序
基本思想
当插入第i(i≥1)个对象时,前面的V[0],V[1],…,V[i−1]已经排好序。这时,用V[i]的排序码与V[i−1],V[i−2],…,V[0]的排序码顺序进行比较,找到插入位置即将V[i]插入,原来位置上的对象向后顺移。
C#代码
/// <summary>
/// 插入排序
/// </summary>
/// <param name="Array">待排序数组</param>
/// <param name="N">数组元素个数</param>
/// <returns></returns>
public static int[] InsertionSort(int[] Array, int N)
{
int j, P;
int Tmp;
for (P = 1; P < N; P++)
{
Tmp = Array[P];
for (j = P; j > 0 && Array[j - 1] > Tmp; j--)
{
Array[j] = Array[j - 1];
}
Array[j] = Tmp;
}
return Array;
}
直接插入算法分析
设待排序对象个数为n,则该算法的主程序执行n−1趟排序码比较次数和对象移动次数与对象排序码的初始排列有关。
- 最好情况下,排序前对象已经按照要求的有序。比较次数(KCN):n−1 ; 移动次数(RMN):为0。则对应的时间复杂度为O(n)。
- 最坏情况下,排序前对象为要求的顺序的反序。第i趟时第i个对象必须与前面i个对象都做排序码比较,并且每做1次比较就要做1次数据移动(具体可以从下面给出的代码中看出)。比较次数(KCN):∑n−1i=1i=n(n−1)2≈n22 ; 移动次数(RMN):为∑n−1i=1i=n(n−1)2≈n22。则对应的时间复杂度为O(n2)。
- 如果排序记录是随机的,那么根据概率相同的原则,在平均情况下的排序码比较次数和对象移动次数约为n24,因此,直接插入排序的时间复杂度为O(n2)。
直接插入算法特点
- 它是稳定排序,不改变相同元素原来的顺序。
- 它是in-place排序,只需要O(1)的额外内存空间。
- 它是在线排序,可以边接收数据边排序。
- 它跟我们牌扑克牌的方式相似。
- 对小数据集是有效的。
完整代码被我放在了Github上,感兴趣的可以下下来看一下https://github.com/Finish-Dream/DSAlgorithm