写在前面

计数排序,基数排序

总结

计数排序是非基于比较的排序方式,和一般基于比较的排序不同。
基于比较的排序的算法的平均复杂度的下界也是o(nlgn)。但是对于某些特定情况的输入来说可以使用非比较排序算法使得复杂度降低。

如果输入的数据是非负整型值,而且元素的最大值是一个有限的值K,那么在K不是特别大的情况下是可以得到o(n)的排序算法的。当数据长度n和K在一个数量级的情况下,计数排序就能够达到效果,当k为n的多项式级别基数排序可以达到效果。

基数排序实现

#include <iostream>
#include <vector>
using namespace std;
/** * 基数排序。 * 采用的基数是10,那么每个桶的范围就是0,1,2,3,4,5,6.。。9 * 对每个元素按照位从低到高做计数排序 时间复杂度为o(n+9) * 一共需要做的趟数是最大的元素的的位数k * 总时间复杂度为O(k*n)当最大值为n的多项式级别是时k为常数级别。 * 总体时间复杂度为o(n) */


int getDigitNumber(int x) {

    int n = 0;
    while(x>0) {
        x /= 10;
        ++n;
    }
    return n;
}

int getD(int x,int d) {
    int val = 0;
    while(d) {
        val = x%10;
        x /= 10;
        --d;
    }
    return val;
}

/* 计数排序: 1.开辟一个长度为基数b的桶 2.开辟一个临时的数组 3.对于每一个元素的第d位在桶中计数 3.将桶当中的值进一步修改为该值应该出现在的最大位置的下一个 4.从后往前遍历元素放置每一个元素到临时数组的指定的位置。 5.将临时数组拷贝回原始数组。 */
void count_sort(vector<int>& vec,int d) {

    vector<int> table(10,0);
    vector<int> tempVec(vec.size(),0);

    for(int i=0;i<vec.size();++i) 
        table[getD(vec[i],d)%10] += 1;


    for(int i=1;i<10;++i) 
        table[i] += table[i-1];

    for(int i=vec.size()-1;i>=0;--i) {
        int j = getD(vec[i],d)%10;
        tempVec[table[j]-1] = vec[i];
        table[j] -= 1;
    }
    for(int i=0;i<vec.size();++i) 
        vec[i] = tempVec[i];
    return;
}

/* 基数排序: 1.遍历数组找到最大值 2.获取该最大值的位数 3.从低位开始迭代计数排序 */
void redix_sort(vector<int>& vec) {
    int n = vec.size();
    if(n<=1) return;

    int m = 0;
    for(int i=0;i<n;++i) {
        m = max(vec[i],m);
    }

    int d = getDigitNumber(m);

    for(int i=1;i<=d;++i)
        count_sort(vec,i);
    return;
}


/* 测试代码 */
int main()
{
    vector<int> vec{123,4,55,78,9,223,4,12,44,345,1234,1222};

    redix_sort(vec);

    for(auto each:vec)
        cout << each << endl;
    return 0;
}