C++ 计数排序详解

计数排序是一种高效的排序算法,尤其适用于数据范围较小的情况。它通过统计元素出现的次数来排序,不涉及元素之间的比较。

1. 知识点介绍

计数排序是一种非比较型的排序算法,其核心思想是通过统计待排序元素中每个元素出现的次数,然后按照元素的大小顺序依次输出元素。计数排序的时间复杂度为O(n+k),其中n是待排序元素的数量,k是元素的取值范围。

计数排序的特点:

  • 适用于数据范围较小的情况
  • 不需要进行元素之间的比较
  • 时间复杂度较低
  • 需要额外的存储空间

计数排序的基本步骤:

  1. 找出待排序数组中的最大值和最小值
  2. 创建一个计数数组,用于统计每个元素出现的次数
  3. 根据计数数组中的数据,将原数组中的元素按照顺序重新排列

2. 基本操作

2.1 声明与初始化

在实现计数排序时,需要声明并初始化原数组和计数数组。


#include <iostream>
using namespace std;

int main() {
    // 原数组
    int arr[] = {4, 2, 3, 1, 5, 3};
    int n = sizeof(arr) / sizeof(arr[0]);
    
    // 找出最大值和最小值
    int max = arr[0], min = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max) max = arr[i];
        if (arr[i] < min) min = arr[i];
    }
    
    // 创建计数数组
    int count[max - min + 1] = {0};
    
    return 0;

2.2 访问元素

通过遍历原数组,统计每个元素出现的次数并存储到计数数组中。


#include <iostream>
using namespace std;

int main() {
    int arr[] = {4, 2, 3, 1, 5, 3};
    int n = sizeof(arr) / sizeof(arr[0]);
    
    int max = arr[0], min = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max) max = arr[i];
        if (arr[i] < min) min = arr[i];
    }
    
    int count[max - min + 1] = {0};
    
    // 统计元素出现次数
    for (int i = 0; i < n; i++) {
        count[arr[i] - min]++;
    }
    
    return 0;

2.3 遍历数组

根据计数数组中的数据,将原数组中的元素按照顺序重新排列。


#include <iostream>
using namespace std;

int main() {
    int arr[] = {4, 2, 3, 1, 5, 3};
    int n = sizeof(arr) / sizeof(arr[0]);
    
    int max = arr[0], min = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max) max = arr[i];
        if (arr[i] < min) min = arr[i];
    }
    
    int count[max - min + 1] = {0};
    
    for (int i = 0; i < n; i++) {
        count[arr[i] - min]++;
    }
    
    // 重新排列原数组
    int index = 0;
    for (int i = 0; i < max - min + 1; i++) {
        while (count[i] > 0) {
            arr[index++] = i + min;
            count[i]--;
        }
    }
    
    return 0;

2.4 修改元素

在计数排序过程中,原数组的元素会被重新排列,因此需要修改原数组中的元素值。


#include <iostream>
using namespace std;

void countingSort(int arr[], int n) {
    int max = arr[0], min = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max) max = arr[i];
        if (arr[i] < min) min = arr[i];
    }
    
    int* count = new int[max - min + 1]{0};
    
    for (int i = 0; i < n; i++) {
        count[arr[i] - min]++;
    }
    
    int index = 0;
    for (int i = 0; i < max - min + 1; i++) {
        while (count[i] > 0) {
            arr[index++] = i + min;
            count[i]--;
        }
    }
    
    delete[] count;
}

int main() {
    int arr[] = {4, 2, 3, 1, 5, 3};
    int n = sizeof(arr) / sizeof(arr[0]);
    
    countingSort(arr, n);
    
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    
    return 0;

3. 应用场景

计数排序在实际开发中应用广泛,以下是一些常见场景:

  • 对数据范围较小的数组进行排序
  • 作为其他排序算法的基础步骤,如基数排序
  • 处理统计类问题,如统计某个范围内元素的出现次数
  • 用于需要高效排序且数据分布集中的场景
计数排序应用场景示意图
图:计数排序在不同场景中的应用示意

4. 对比分析

计数排序与其他排序算法的对比:

排序算法 时间复杂度 空间复杂度 稳定性 适用场景
计数排序 O(n+k) O(k) 稳定 数据范围较小的情况
冒泡排序 O(n²) O(1) 稳定 数据规模较小的情况
快速排序 O(nlogn) O(logn) 不稳定 通用场景
归并排序 O(nlogn) O(n) 稳定 对稳定性要求较高的场景

5. 练习题推荐

以下是一些有助于巩固计数排序知识的练习题:

  1. 实现计数排序算法
  2. 计数排序变种问题
  3. 统计元素出现次数
  4. 基于计数排序的简单应用
  5. 计数排序优化问题