C++计数排序

计数排序(Counting sort)是一种稳定的线性时间排序算法。

当输入的元素是 n个min到max之间的整数时候,k = max - min +1,它的时间复杂度是O(n+k)。
计数排序不是比较排序,排序的速度快于任何比较排序算法。当然这是一种牺牲空间换取时间的做法,而且当O(k)>O(nlog(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在理论上的下限是O(nlog(n)),如归并排序,堆排序)

例如:{0,-1,3,2,7,0,1,2,1},这里min = -1,max = 7,那么k = max - min + 1 = 9,需要一个大小为k的辅助数组。统计[min,max]之间数字出现的次数.
步骤:

  1. 找到待排序数组的最大值和最小值;
  2. 统计数组中每个数字出现的次数,存入辅助数组中;
  3. 对辅助数组总数累计(后面的值出现的位置为前面所有值出现的次数之和);
  4. 逆序输出辅助数组中的值。

代码:

#include <iostream>
#include <vector>
using namespace std;
void countSort(vector<int>& arr)
{
    int len = arr.size();
    if(len == 0)
        return;
    //这里需要一个原始的数组拷贝
    vector<int> tempArr(arr.begin(),arr.end());
    //查找min,max
    int min = tempArr[0],max = min;
    for(int i=1;i<len;++i)
    {
        if(min>tempArr[i])
            min = tempArr[i];
        if(max<tempArr[i])
            max = tempArr[i];
    }

	//计算k值
    const int k = max-min+1;
    int count[k]={0};
    for(int i=0;i<len;++i)
        ++count[tempArr[i]-min];//这里需要一个偏移量min,因为数组是从下标0开始的,统计次数
    for(int i=1;i<k;++i)
        count[i] +=count[i-1];//后面的键值出现的位置为前面所有键值出现的次数之和,也就是每个数所在的范围

	//这里是逆序排序,这个和我们统计每个数字出现的位置有关系,
	//比如0出现了3次,加上之前-1出现的次数,就是4。
	//我们倒序排序第一个key值为0的时候,那么在count中的大小应该是4,那么它在arr数组的下标就该是4-1,count自减1为3
	//排序第二个key值为0的时候,count为3,在arr数组的下标是3-1
    for(int i=len-1;i>=0;--i)
        arr[--count[tempArr[i] - min]] = tempArr[i]; 
        //这里--count[tempArr[i] - min]很精简
        //又解决了下标需要减1的问题,对应的count数组中的值也减1

}

int main()
{
    vector<int> arr{-1,3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4,
                    7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };
    countSort(arr);
    for(auto value:arr)
        cout<<value<<" ";
    cout<<endl;
    return 0;
}

输出结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zqw_yaomin/article/details/82829589