美文网首页
算法:排序(三)

算法:排序(三)

作者: 熊白白 | 来源:发表于2017-07-03 21:14 被阅读21次

计数排序与基数排序

利用桶排序的思想可以达到O(N)的时间复杂度,但仅限于特定的情况。

计数排序

已知数据取值在狭小且有限的集合内,则可以使用计数排序。思路是预先准备好表征元素取值的计数桶,遍历元素时,使得表征该元素取值的桶计数值加一。遍历完成后倒出元素即可。

int* countingSort(int* A, int n) {
    //获取最大最小值以便分配桶
    int min=A[0],max=A[0];
    for(int i=1;i<n;++i){
        if(A[i]>max)
            max=A[i];
        if(A[i]<min)
            min=A[i];
    }
    //分配桶:一个计数数组
    int* ss=new int[max-min+1]();
    //对每个元素找到其对应的桶
    for(int i=0;i<n;++i)
        ss[A[i]-min]++;
    //遍历所有的桶,把元素倒回去
    int pos=0;
    for(int i=0;i<max-min+1;++i){
        while(ss[i]--){
            A[pos++]=i+min;
        }
    }
    delete[] ss;
    return A;
}

基数排序

基数排序可以看做是计数排序的扩展。适用于元素有多个键值,键值取值狭小且有限的情况。思路是按照键值优先级从低到高进行排序。
举例:正整数的个位/十位/百位数字就是表征数字大小的各个键值,先按照个位数字放入各个桶内,然后倒出;再按照十位/百位数字继续此操作。

CODE

int* radixSort(int* A, int n) {
    const int M=10;
    //临时存储数据
    int* s=new int[n];
    //计数:每个键值各对应多少元素
    int* c=new int[M]();
    //被除数,用以计算当前位置的数字
    int x=1;
    int number;
    for(int t=0;t<5;++t){  //假设元素不超过五位数
        //清零计数数组
        for(int m=0;m<M;++m)
            c[m]=0;
        //统计数组中各个number的数目
        for(int i=0;i<n;++i){
            number=A[i]/x%10;
            c[number]++;
        }
        //c数组做累加操作
        for(int m=1;m<M;++m)
            c[m]=c[m-1]+c[m];
        //经过累加后,c[m]表示第m号桶的终止位置后一位
        //正是因此,我们放桶的时候从后往前放.
        for(int i=n-1;i>=0;--i){
            number=A[i]/x%10;
            s[--c[number]]=A[i];
        }
        //从桶中倒回数组
        for(int i=0;i<n;++i){
            A[i]=s[i];
        }
        x*=10;
    }
    delete[] s;
    delete[] c;
    return A;
}

注意

  • 以上代码为了节省空间,所有的桶都位于数组s上的某一段,通过计数产生c数组,然后累加得到每个桶的尾后指针位置,以此访问桶。


  • 元素入桶时根据尾后指针进行遍历,所以需要从后向前遍历数组。
  • 如果不考虑空间花费,可以通过指针数组来创建类似于二维数组的结构来构造M个桶;或者使用队列等数据结构来处理。

相关文章

网友评论

      本文标题:算法:排序(三)

      本文链接:https://www.haomeiwen.com/subject/noxacxtx.html