Introduction to Algorithm(chapter 8)

基于比较的排序都有一个下界w(n*lgn),因为基于比较的排序都可以通过建立一颗决策树来表示,其中叶子节点代表最终的排序结果,这颗树共有n!个叶子,那其中从根到叶子的最长路径就代表了最坏情况下的比较次数,即树的高度h。对于一颗h高的树,叶子节点不多2^h,而这颗决策树的叶子个数为n!故,n!<=2^h..->  h>=lg(n!) = w(n*lgn),故基于比较的排序都有此下界。

而计数排序则不是基于比较的排序,它利用了元素的大小特点并采用一定的辅助空间来完成排序,假设一组数A[n](序号0...n-1),其中每一个元素大小在0...k之间,那么就可以利用一个辅助数组C[k+1](序号0...k)来完成排序,先初始化C[i]=0,然后遍历A[i],统计每个A[i]出现的次数即C[A[i]]++,这步操作后C[i]就代表i一共出现了多少次,然后遍历C并

C[i] = C[i]+C[i-1],这步操作后C[i]就代表了小于等于i的元素共出现了多少次,例如假设A[i] = 5,C[A[i]]= 3,那么就代表小于等于5的元素出现了三个,那么我们就应该将5放在第三个位置上即B[C[A[i]]-1] = A[i](注意第三个位置对应于C语言中的B[2]故C[A[i]]-1对应于C语言中的下标),因为可能存在不止一个5,所以放置过5后,我们要减少小于等于5出现的次数即C[A[i]]--,这样如果还有5出现的话那么它应该放置在第二个位置上。

算法:

// a array of n elements whose element is between 0---k
void countSort(int A[],int B[],int n,int k)
{
int* C = new int[k+1];//对应于0...k
for(int i=0;i<=k;i++)
C[i] =0;
for(int i=0;i<n;i++)
C[A[i]]++;//C[i]:i出现的次数
for(int i=1;i<=k;i++)
C[i] = C[i]+C[i-1];//C[i]:小于等于i的个数
print(C,k+1);

       //注意这里采用的是从后往前遍历,这样就保证了算法的稳定性,假如初始A中有两个相同的数...6....6,而且C[6] =  //10,那么从后往前遍历时遇到第一个6时将6放置在10位置处同时C[6]-- = 9,往前遍历遇到第二个6时那么这个6就放  //置在9位置处,这样就保证了计数排序是稳定的。
for(int j =n-1;j>=0;j--) 
{
B[C[A[j]]-1] = A[j];//将每个A[j]放在和自己排名对应的地方
C[A[j]]--;//可能出现多个A[j],故减1以使下一次出现时将它放在前一个位置上而不重叠
}
delete []C;
}

计数排序思想有点类似于考试排名,给每个学生一个排名,那么对结果排序时就应该将该学生信息放到和排名对应的栏目中,如果出现考试排名相同的情况那么即将相同的放到前一个位置,不同点即是计数排序利用了元素本身大小的信息而考试排名没用到,但将信息放到和排名对应的位置这点思想还是相似的。

 

习题8后面有个水壶配对的思考题,这个问题的答案很精彩,利用了快排的的思想,值得关注。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值