• 计数排序.


      一.定义:

    计数排序(Counting Sort)是一种非比较性质的排序算法,其时间复杂度为O(n+k)(其中n为待排序的元素个数,k为不同值的个数)。这意味着在数据值范围不大并且离散分布的情况下,规模越大,排序速度越快的特点。然而,如果数列元素不满足整数和有确定范围的条件,则不能使用计数排序。

    二.原始代码:

    1. #include
    2. #include
    3. #include
    4. // 计数排序
    5. void count_sort(int num[], int len) {
    6. // 寻找最大值
    7. int max = num[0];
    8. for (int i = 1; i < len; i++) {
    9. max = max > num[i] ? max : num[i]; // 更新最大值
    10. }
    11. int range = max + 1; // 计数数组的长度为最大值加1
    12. int *arr = (int *)malloc(sizeof(int) * range); // 申请空间
    13. memset(arr, 0, sizeof(int) * range); // 初始化计数数组为0
    14. for (int i = 0; i < len; i++) {
    15. arr[num[i]]++; // 对每个元素进行计数
    16. }
    17. // 填充原数组
    18. int j = 0;
    19. for (int i = 0; i < range; i++) {
    20. while (arr[i] != 0) { // 将计数数组中的每个非零元素放回原数组
    21. num[j] = i; // 填充元素
    22. arr[i]--; // 计数减一
    23. j++; // 标记原数组填充到的位置
    24. }
    25. }
    26. free(arr); // 释放计数数组空间
    27. }
    28. int main() {
    29. int num[12] = { 5, 8, 5, 4, 6, 8, 9, 7, 2, 3, 4, 5 };
    30. count_sort(num, 12); // 执行计数排序
    31. // 打印结果
    32. for (int i = 0; i < 12; i++)
    33. {
    34. printf("%d ", num[i]);
    35. }
    36. return 0;
    37. }

    输出结果:

    2 3 4 4 5 5 5 6 7 8 8 9

    代码优点:

    1. 计数排序是一个非比较排序算法,对于一个给定的输入数组,不论数组中的数字如何分布,其时间复杂度始终稳定在O(n)。
    2. 擅长处理小范围大量重复的整数数据,效率非常高,实际运行速度通常比其他的O(n log n)比较类排序算法要快。

    代码缺点:

    1. 计数排序算法只能用来排序整数,并且只能处理非负整数,对于负整数和小数,此算法无法正常工作,需要进行额外处理才能排序。
    2. 该排序算法需要额外的空间来存储计数数组,如果输入数据的范围(最大值-最小值)过大,将会导致空间的大量浪费。
    3. 如果待排序的数列中最大和最小数值的差过大,需要很大的辅助空间,因此空间复杂度显著上升,空间效率低。
    4. 计数排序是一种不稳定的排序,无法保证相同数值的元素在排序后保持原有的顺序。

    三.优化代码:

    1. #include
    2. #include
    3. #include
    4. // 计数排序函数
    5. void count_sort(int num[], int len) {
    6. int max = num[0]; // 初始化最大值为数组第一个元素
    7. int min = num[0]; // 初始化最小值为数组第一个元素
    8. // 找出数组中最大值和最小值
    9. for (int i = 1; i < len; i++) {
    10. max = max > num[i] ? max : num[i];
    11. min = min < num[i] ? min : num[i];
    12. }
    13. int range = max - min + 1; // 计算最大值与最小值的差值和1(确定结果数组的大小)
    14. // 动态分配range大小的计数数组,并初始化为0
    15. int *arr = (int *)malloc(sizeof(int) * range);
    16. memset(arr, 0, sizeof(int) * range);
    17. // 计算每个元素出现的次数
    18. for (int i = 0; i < len; i++) {
    19. arr[num[i]-min]++; // 使用当前元素值减去最小值作为索引
    20. }
    21. // 按升序排列原数组
    22. for (int i = 0, t = 0; i < range; i++) {
    23. while (arr[i] != 0) {
    24. num[t] = i + min; // 使用当前索引加上最小值得到原始值
    25. t++;
    26. arr[i]--; // 减去一个元素的计数
    27. }
    28. }
    29. // 释放动态分配的计数数组空间
    30. free(arr);
    31. }
    32. int main() {
    33. // 待排序的数组
    34. int num[10] = { -10, 10, -9, 9, 8, 7, 7, 6, 6, 6 };
    35. // 使用计数排序算法进行排序
    36. count_sort(num, 10);
    37. // 输出排序后的数组元素
    38. for (int i = 0; i < 10; i++) {
    39. printf("%d ", num[i]);
    40. }
    41. return 0;
    42. }

    优化点:

    1.可以实现包含负数的数组排序

  • 相关阅读:
    进阶笔录-深入理解Java线程之Synchronized
    【算法】栈和队列常见算法
    VQGAN理论加代码一对一详解,小白向解析
    Git 基本操作【本地仓库与远程仓库的推送、克隆和拉取】
    React中组件之间如何通信?
    Android SurfaceFlinger——Vsync信号发送(五十二)
    Hexagon_V65_Programmers_Reference_Manual(40)
    静态库与动态库笔记
    (黑马出品_07)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
    06-JVM对象内存回收机制深度剖析
  • 原文地址:https://blog.csdn.net/2303_76295261/article/details/134488693