学习《算法导论》第八章 计数排序 总结

学习《算法导论》第八章 计数排序 总结

前面学习的排序算法都是基于比较的. 下面学习的计数排序不是基于比较的,代码中并没出现元素之前的比较. 当我们不采用基于比较排序的模型时,排序算法的下界Ω(nlgn)在这里就不适用了. 但计数排序作了某种假设,即假设输入的元素是由一个小范围内的整数构成的.

计数排序概论

计数排序有个前提就是假设n个输入元素中的每个元素都是介于0到k之间的整数. 计数排序的运行时间是Θ(n).
计数排序的思想是:对每个输入元素x,确定出小于x的元素个数. 有了这个信息,就知道x在最后的排序数组中位于哪个位置.

计数排序的算法

这里需要两个辅助数组:
A[1…n]:待排序数组,每个元素的值都位于0到k之间.
C[0…k]: 临时数组,k为待排序数组中最大的值.
B[1…n]: 存放排序结果的数组.

COUNTING-SORT(A, B, k)
1   for i to k
2      do C[i] ← 0
3   ► C[A[j]]表示A[j]出现的次数,即等于A[j]的元素个数
4   for j ← 1 to length(A)
5      do C[A[j]] ← C[A[j]] + 1
6   ► 此时,C[i]表示小于或等于i的元素个数
7   for i ← 1 to k
8      do C[i] ← C[i] + C[i - 1]
9   ► 下面的部分挺难理解
10  for j ← length[A] downto 1
11     do  B[C[A[j]]] ← A[j]
12         C[A[j]]--

第10行到第12行比较难理解. 到第8行我们知道数组C的下标为数组A中的元素,数组C的元素值为:小于或等于数组C的下标(小于等于数组A中的该元素)的元素个数. 那么第11行就能理解了,因为若知道有10个元素比x要小,那么可以肯定x的位置为11(算法中包含了相等的情况).这里举个例子吧,如果A[3] = 8;C[A[3]] = C[8] = 6,则表示小于等于8的元素有6个. 那么A[3]这个元素在最终排序数组中的位置为6. 也就是,B[C[A[3]]] = B[C[8]] = B[6] =8.

计数排序的时间复杂度分析

由算法可知,第1-2行的for循环所用的时间为Θ(k),第3-4行的for循环所用的时间为Θ(n),第6-7行的for循环所用的时间为Θ(k),第9-11行的for循环所用的时间为Θ(n). 所以,总的时间就是Θ(k +n). 可知,计数排序的时间下界是优于Ω(nlgn).
计数排序还有一个重要的性质就是:稳定性. 即具有相同值的元素在输出数组中的相对次序与它们在输入数组中的次序是相同的.

计数排序运行过程

略(可以自己写个简单数组,模拟运行过程)

计数排序的代码实现

void CountingSort 
(int* InArray, 
int ArrayLength,
 int* OutArray,
 int ArrayNumber)
{
    int LoopIdOne = 0;
    int LoopIdTwo = 0;

      // 申请临时数组,存放小于等于某元素的元素个数
    int* ArrayTemp = (int*)malloc(sizeof(int) * ArrayNumber);
      if (NULL == ArrayTemp)
{
    return;
}

// 初始化临时数组
for (LoopIdOne = 0; LoopIdOne < ArrayNumber; LoopIdOne++)
{
    ArrayTemp[LoopIdOne] = 0;
}

    // 计算输入数组中包含InArray[LoopIdTwo]元素的元素个数
    for (LoopIdTwo = 0; LoopIdTwo < ArrayLength; LoopIdTwo++)
    {
        ArrayTemp[InArray[LoopIdTwo]] = InArray[LoopIdTwo] + 1;
}

// 计算输入数组中小于等于InArray[LoopIdTwo]的元素个数
for (LoopIdOne = 1; LoopIdOne < ArrayNumber; LoopIdOne++)
{
    ArrayTemp[LoopIdOne]
 = ArrayTemp[LoopIdOne] + ArrayTemp[LoopIdOne - 1];
}

// 排序
for (LoopIdTwo = ArrayLength; LoopIdTwo > 0; LoopIdTwo--)
{
    OutArray[ArrayTemp[InArray[LoopIdTwo]]]
                   = InArray[LoopIdTwo];
        ArrayTemp[InArray[LoopIdTwo]--;
}

free(ArrayTemp);

    return;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值