基本思想
计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。
计数排序的基本思想是:对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数。一旦有了这个信息,就可以将x直接存放到最终的输出序列的正确位置上。例如,如果输入序列中只有7个元素的值小于x的值,则x可以直接存放在输出序列的第8个位置上。当然,如果有多个元素具有相同的值时,我们不能将这些元素放在输出序列的同一个位置上,因此,上述方案还要作适当的修改。
计数排序步骤
- 找出待排序的数组中最大和最小的元素
- 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
- 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
- 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
有三个参数:
- 输入数组sourceArr[], 长度为sourceArr.size(),
- 需要一个数组存放结果resultArr,长度大小跟sourceArr相同。
- 另外需要一个辅助数组,tempArr,长度大小为sourceArr中最大的元素值。
参考代码
#include "iostream"
#include "vector"
using namespace std;
class countSort{
public:
static void CSort(vector<int> sourceArr, vector<int> resultArr, const int maxNum)
{
vector<int> tempArr(maxNum+1);//注意分配给临时数组的大小为maxNum+1,因为后面要访问到tempArr[maxNum]
for (int i = 0; i < tempArr.size(); i++)
tempArr[i] = 0;
for (int i = 0; i < sourceArr.size(); i++)
{
tempArr[sourceArr[i]]++;
}
//注意<=是小于等于maxNum,不要漏掉最后一个元素,开始从i=1
for (int i = 1; i <= maxNum; i++)
tempArr[i] += tempArr[i - 1];
//注意tempArr[sourceArr[i]] - 1 代表的是sourceArr[i]在结果数组中的位置
//在放好之后要减一 因为有重复值相等的数
for (int i = sourceArr.size() - 1; i >= 0; i--)
{
resultArr[tempArr[sourceArr[i]] - 1] = sourceArr[i];
tempArr[sourceArr[i]]--;
}
//输出查看结果
for (int i = 0; i < resultArr.size(); i++)
cout << resultArr[i] << " ";
cout << endl;
}
int getMaxNum(vector<int> arr)
{
int max = 0;
for (int i = 0; i < arr.size(); i++)
{
if (arr[i] > max)
max = arr[i];
}
return max;
}
};
int main()
{
vector<int> arr = { 0, 2, 12, 3, 0, 2, 3, 0, 3,5,5,2,3,7,8,4};
vector<int> ans(arr.size());
countSort csort;
int max = csort.getMaxNum(arr);
csort.CSort(arr, ans, max);
return 0;
}
时间复杂度:O(n+maxNum)
空间复杂度:O(n+maxNum)
注意:计数排序是稳定的排序方法。
1. 计数排序是有效的,如果输入数据的范围是不显著大于数字的个数。
2. 它不是一个基于比较的排序。它运行的时间复杂度为O(n)
3. 它经常被用来作为另一个排序算法像基数排序的一个子程序。
4. 计数排序可以扩展到负输入也可以。
2. 它不是一个基于比较的排序。它运行的时间复杂度为O(n)
3. 它经常被用来作为另一个排序算法像基数排序的一个子程序。
4. 计数排序可以扩展到负输入也可以。
参考资料:
http://baike.baidu.com/view/1209480.htm?wtp=tt