概述
下面分别介绍常用的内部排序算法:计数排序、冒泡排序、选择排序、堆排序、插入排序、归并排序、快速排序、基数排序,桶排序,为了便于描述,都以非递减(<=)排序为例。我认为可以从数据规模、时间复杂度、辅助空间数量、算法适用的情况(如适用于顺序存储还是链式存储)以及算法的稳定性方面来进行分析。参考数据结构(严蔚敏版),算法设计与分析基础(第二版,Anany Levitin著,潘彦译)。
计数排序
下面以数组为例介绍计数排序,假如带排序数组为A[],数组元素个数为n,起始索引为0.
比较计数排序
比较计数排序仅仅是为了说明计数排序的思想,它通过一个辅助数组D[],D[i]表示A[]中比A[i]大的元素个数,最后将A[i]放到结果数组S[D[i]]的位置,伪代码如下:
D[0- n-1]=0;
for(i=0;i<n-1;++i)
for(j=i+1;j<=n-1;++j)
if(A[i]<A[j])
++D[i];
else
++D[j];
for(i=0;i<=n-1;++i)
S[D[i]]=A[i];
显然时间复杂度是O(n^2),辅助空间复杂度O(n),稳定,所以比较计数排序很少在实际中应用。
分布计数排序
假如数组A的元素值位于下界l和上界u之间,我们可以扫描一遍数组A,统计出l至u之间每个可能值出现的次数存入D[0 -- u-l]中,然后将结果数组的前D[0]个填入l,接下来的D[1]个填入l+1,依次类推。算法的伪代码:
DistributionCounting(A[0...n-1],l,u){
D[0 - n-1]=0;
for(i=0;i<=n-1;++i)
++D[A[i]-l];
for(i=1;i<=u-1;++i)
D[i]+=D[i-1];//值为i的元素放入的结束位置
for(i=n-1;i>=0;--i){
j=A[i]-l;
S[--D[j]]=A[i];
}
}
显然时间复杂度是O(n),辅助空间复杂度O(n),且稳定。
使用一个结果数组S[]保存结果,而不是直接用A保存的原因是,有时不能只简单的复制键值,元素可能包含其他信息。
适用条件: