目录
前言
计数排序算法是必须掌握的一种基础算法,在一些比较出名的竞赛acm、蓝桥杯,并且在一些公司面试题中都可能会出现,而且作为简单题我们必须要拿下,所以我们要引起重视,下面让我们来深入了解计数排序算法。
一、什么是计数排序
计数排序(Counting Sort)是一种非比较型整数排序算法,适用于一定范围内的整数排序。其基本思想是通过计数来确定每个值在数组中出现的次数,然后根据这些计数来确定每个元素在排序后数组中的位置。计数排序的时间复杂度为 O(n + k),其中 n 是待排序数组的长度,k 是待排序数组中的最大值与最小值之差,计数排序适用于元素范围较小的整数排序问题,如果元素范围过大,则计数数组会占用大量内存空间。
二、计数排序算法的步骤
1.找出数组中的最大值和最小值:
遍历数组,找出数组中的最大值 max 和最小值 min。
2.创建计数数组:
创建一个计数数组 count,大小为 max - min + 1。
初始化计数数组中的所有元素为 0。
3.计算每个元素的出现次数:
遍历待排序数组,对每个元素 arr[i],计算其对应的计数 count[arr[i] - min],并递增。
4.计算位置索引:
修改计数数组,使其存储的是每个值在排序后数组中的位置索引。
对计数数组进行累加,即 count[i] += count[i - 1]。
5.构建输出数组:
创建一个输出数组 output,大小为原数组的长度 n。
遍历原数组,根据计数数组中的索引信息将元素放入输出数组的正确位置。
每放入一个元素后,对应的计数减 1。
6.将排序后的数组复制回原数组(如果需要):
将输出数组 output 中的元素复制回原数组 arr(如果需要保留原数组)。
三、计数排序算法图解
四、计数排序c++代码模板
#include <iostream>
#include <vector>
#include <algorithm> // for std::max_element and std::min_element
void countingSort(std::vector<int>& arr) {
if (arr.empty()) return;
// 1. 找出数组中的最大值和最小值
int minValue = *std::min_element(arr.begin(), arr.end());
int maxValue = *std::max_element(arr.begin(), arr.end());
// 2. 创建计数数组并初始化为0
std::vector<int> count(maxValue - minValue + 1, 0);
// 3. 计算每个元素的出现次数
for (int num : arr) {
count[num - minValue]++;
}
// 4. 计算位置索引(前缀和)
for (size_t i = 1; i < count.size(); ++i) {
count[i] += count[i - 1];
}
// 5. 创建输出数组并构建排序后的结果
std::vector<int> output(arr.size());
for (int i = arr.size() - 1; i >= 0; --i) {
output[count[arr[i] - minValue] - 1] = arr[i];
count[arr[i] - minValue]--;
}
// 6. 将排序后的数组复制回原数组
arr = output;
}
int main() {
std::vector<int> arr = {4, 2, 2, 8, 3, 3, 1};
std::cout << "排序前的数组: ";
for (int num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;
countingSort(arr);
std::cout << "排序后的数组: ";
for (int num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
五、经典例题
1.颜色分类
(帅哥们这个蓝色字体可以点进去看原题)
代码题解
class Solution {
void countingSort(vector<int>&a,int m){//m为值域
int*count=new int[m+1];//申请一个大小为m+1的内春空间
memset(count,0,sizeof(int)*(m+1));//将这个内春空间的所有元素置为0
for(int i=0;i<a.size();i++){
count[a[i]]++;
}
int idx=0;
for(int i=0;i<=m;i++){
while(count[i]>0){
a[idx++]=i;
count[i]--;
}
}
delete[]count;//释放内存避免内存泄漏
}
public:
void sortColors(vector<int>& nums) {
countingSort(nums,2);
}
};
2.最后一块石头的重量(这一道题之前的作品就有)
(帅哥们这个蓝色字体可以点进去看原题)
代码题解
class Solution {
void countingSort(vector<int>&a,int m){
int *count=new int[m+1];
memset(count,0,sizeof(int)*(m+1));
for(int i=0;i<a.size();i++){
count[a[i]]++;
}
int idx=0;
for(int i=0;i<=m;i++){
while(count[i]>0){
a[idx++]=i;
count[i]--;
}
}
}
public:
int lastStoneWeight(vector<int>& stones) {
while(stones.size()>1){
int n=stones.size();
countingSort(stones,1000);
int x=stones[n-1]-stones[n-2];
stones.pop_back();
stones.pop_back();
if(x!=0||stones.size()==0)stones.push_back(x);
}
return stones[0];
}
};
3. 学生分数的最小差值(这道题之前的排序算法的作品也有过,不同方法)
(帅哥们这个蓝色字体可以点进去看原题)
代码题解
class Solution {
void countingSort(vector<int>&a,int m){
int*count=new int[m+1];
memset(count,0,sizeof(int)*(m+1));
for(int i=0;i<a.size();i++){
count[a[i]]++;
}
int idx=0;
for(int i=0;i<=m;i++){
while(count[i]>0){
a[idx++]=i;
count[i]--;
}
}
}
public:
int minimumDifference(vector<int>& nums, int k) {
countingSort(nums,100000);
int ret=1000001;
for(int i=0;i+k-1<nums.size();i++){
int l=i;
int r=l+k-1;
ret=min(ret,nums[r]-nums[l]);
}
return ret;
}
};
六、结语
学习算法是一个很艰难,漫长的过程,我们要克服一切困难,学习算法本就是由易到难,我相信通过我们坚持不懈的努力一定能理解并熟练掌握其中细节,加油。
关注我让我们一起学习编程,希望大家能点赞关注支持一下,让我有持续更新的动力,谢谢大家