算法笔记七:计数排序

算法思想:

//前提条件:

//待排序集合均为正整数

//已知其最大值(也可以排序的过程中求出)


//思想:假设我知道给定一个数,其前面有N个数比我小,那么,我就知道我应该位于数组中的第几个位置上


//实现方式:对于带排序集合中的每一个数,使用其值作为在另外一个数组中的下标,并将目标数组的值加1,这样,目标数组就记录了待排序集合中的每个元素所出现的次数

//该目标数组称为元素出现次数数组,长度为待排序数组中的最大元素的值+1


//然后我们再对出现次数数组,做一下转换:从第一个位置开始,让其值等于前面一个值与当前值的和,这样,这个处理过的出现次数数组就变成了,值等于5的数字,前面有多少个元素要小于等于5,也就实现了我们的一个核心思想:知道了前面有多少个数比我小,也就知道了我应该位于数组中的第几个位置上


从思想上来看,分为一下几步:

1、初始化一个大小为待排序集合最大值k+1的一个数组

空间代价 O(k)

2、遍历待排序集合,使用值作为下标,将k+1数组中的该下标位置上的值+1,也就是记录下这个数字一共出现了多少次

时间代价O(n)

3、整理下次数统计数组,转换为“该数字前面有多少个数字出现”

时间代价O(K)

4、初始化一个结果集数组

空间代价O(n)

5、从后往前遍历待排序数组,通过其在次数统计数组中的值,得出前面有多少个数字,也就是该数字当前应该放在第几个位置,将其放入到新的结果集数组中

时间代价O(n)

第五部中从后往前遍历待排序数组,保证了排序算法的稳定性


结论:一个最大值为k的n个元素的待排序数组,其执行计数排序的时间代价为:

O(2n+k),空间代价为O(n+k)

显然,二者都是一个线性的代价,比前面说的所有的比较排序的最优代价nlgn均表现良好


算法实现:

class CountingSort {
    
    
public:
    //求最大值
    int caculateMaxValue(int * data,int size){
        int maxValue = *data;
        for (int i =1; i < size ; i++) {
            if(*(data + i) > maxValue){
                maxValue = *(data + i);
            }
        }
        return maxValue;
    }
    
    
    //初始化一个元素为0、长度为size的数组
    int * initZeroData(int size){
        int * data =  new int [size];
        memset(data, 0, sizeof(int) * size);
        return data;
    }
    
    //构建 出现次数 数组
    int * buildCountingArray(int * data,int maxValue,int size){
        int * countingArr = initZeroData(maxValue + 1);
        for(int i=0;i<size;i++){
            (*(countingArr + *(data + i)))++;
        }
        return countingArr;
    }
    
    //将 出现次数 数组做下处理,转变成给定的数组,前面有多少个比它小的数字
    void dealCountingArray(int * countingArr,int maxValue){
        for (int i =1; i <= maxValue; i++) {
            *(countingArr + i) += *(countingArr + i -1);
        }
    }
    
    //执行计数排序
    int * doCountingSort(int * data,int size){
        //用来存放结果
        int * resultArr = initZeroData(size);
        
        //求最大值
        int maxValue = caculateMaxValue(data,size);
        
        //每个数字出现的次数统计数组
        int * coutingArr = buildCountingArray(data,maxValue,size);
        
        //处理下次数统计数组,变成某某元素前面有多少个元素比其小
        dealCountingArray(coutingArr,maxValue);
        
        //为了保证稳定性,我们从后往前遍历待排序集合,找出对应的其前面有多少个数比其小的个数,然后定位输出到正确的结果数组中去
        for(int i =size -1;i>=0;i--){
            int beforeLowerNumberCount = *(coutingArr + *(data + i));
            *(resultArr + beforeLowerNumberCount - 1 ) = *(data + i);
            //已经拿走一个了
            *(coutingArr + *(data + i)) = beforeLowerNumberCount - 1;
        }
        
        //清理资源
        delete  [] data;
        delete  [] coutingArr;
        
        return resultArr;
    }
    
    //排序入口
    int * do_sorting(int * data,int size){
        return doCountingSort(data, size);
    }
};

算法总结:

时间代价是线性的,而且是稳定性的排序算法,但是有一定的空间代价和局限性,其虽然突破了比较算法的nlgn的最优代价的上限,但是其有一定的前提必要条件,并且在空间上也有一定的牺牲,使用时要注意其平衡点


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值