必学排序算法——计数排序

前言

计数排序算法是必须掌握的一种基础算法,在一些比较出名的竞赛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;
    }
};

六、结语

学习算法是一个很艰难,漫长的过程,我们要克服一切困难,学习算法本就是由易到难,我相信通过我们坚持不懈的努力一定能理解并熟练掌握其中细节,加油。
在这里插入图片描述
关注我让我们一起学习编程,希望大家能点赞关注支持一下,让我有持续更新的动力,谢谢大家
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值