非比较排序1:计数排序和桶排序

一、计数排序

稳定排序

适用于小数据范围排序

假设待排序序列的元素范围为0~k-1;创建一个长度为k的数组c,c[x]表示在待排序序列中值小于x的元素个数;则x在排序后的序列中的位置即为c[x]

c++代码:

void CountSort(vector<int>& sequence, int max_k)
{
    vector<int> count(max_k+1,0);  // 计数数组,max_k为sequence元素的最大值
    const int c_len = sequence.size();
    vector<int> sort_seq(c_len);
    for(int i=0; i<c_len; ++i)
        ++count[sequence[i]];
    for(int i=1; i<=max_k; ++i)
        count[i] += count[i-1];
    for(int i=c_len-1; i>=0; --i)  //c_len->0维持稳定排序
    {
        sort_seq[count[sequence[i]]-1] = sequence[i];  //-1是因为下标从0开始
        --count[sequence[i]];  //使得后续与sequence[i]相同的元素的位置往前挪1
    }
    sequence = sort_seq;
}

空间复杂度:计数数组count,长度为k;

                    存储排序完成后的序列的数组sort_seq,长度为n(n为待排序序列长度)

                    S(n) = θ(n+k)

时间复杂度:第一个for循环次数 x常数 + 第二个for循环次数 x 常数 + 第3个for循环次数 x 常数

                    T(n) = n x常数 + k x 常数 + n x 常数 = θ(n + k)

如果序列元素的范围太大,比如k=2^32,非常浪费空间;

当k比较小时,T(n)是线性的;

所以计数排序适用于小范围集合排序,比如高考分数排序(总分750,k=750; n很大,几十万学生)

二、桶排序

稳定排序

思想与计数排序相似

计数排序中c[x]就是一个bucket, 桶排序中x表示的是[x1~x2]范围内的数据,即x1<元素<=x2

步骤:

1、创建k个bucket,遍历待排序序列,把元素扔到相应的bucket中

2、对非空的bucket进行排序(可以使用其他排序方法,也可以递归的使用桶排序)

3、按照顺序遍历以上buckets,获得排好序的序列

c++代码:

void BucketSort(vector<int>& sequence, int max_k)
{
    const int c_len = sequence.size();
    //假设一个bucket的范围为[x1~x2],具体bucket的数量,每个bucket中x1,x2的值根据实际情况定
    //这里设置每个bucket中x2-x1=10,第一个bucket的x1为sequence的最小值,设为0
    int x1, x2;
    int d = 10;  //d = x2-x1
    int k = ceil((max_k+1)/float(d));  // bucket的数量
    vector<vector<int> > buckets(k);  //创建k个bucket
    //遍历待排序序列将其中的元素分配到相应的bucket中
    int i, j;
    for(i=0; i<c_len; ++i)
        for(j=0; j<k; ++j)
            if((sequence[i]>=d*j) && (sequence[i]<d*(j+1)))
                buckets[j].push_back(sequence[i]);

    //对每个非空的bucket排序
    for(j=0; j<k; ++j)
        if(!buckets[j].empty())
            ShellSort(buckets[j]);  //使用希尔排序,也可以使用其他排序方法

    //按顺序遍历buckets,获得排好序的序列
    i=0;
    vector<int>::iterator buck_it;
    for(j=0; j<k; ++j)
      if(!buckets[j].empty())
        {
            buck_it = buckets[j].begin();
            while(buck_it!=buckets[j].end())
                sequence[i++] = *buck_it++;
        }
}

空间复杂度:与每个bucket所使用的排序算法有关;

                    首先所有buckets的长度为n (n为待排序序列长度)

                    S(n) = n+

                    公认S(n) = θ(n+k)

时间复杂度:与桶的数量、分配情况等有关

最好情况:    T(n) = θ(n)

最坏情况:    T(n) = θ(n^2)

平均情况:    T(n) = θ(n+k)

猜你喜欢

转载自blog.csdn.net/QW_sunny/article/details/80656113