计数排序c++详解(看这一篇就够了)

计数排序(Counting Sort) 是一种非比较型的整数排序算法,适用于整数范围不大的数据排序。其基本思想是统计待排序数组中每个元素出现的次数,然后通过累加计数信息,将元素放回排序数组中。由于它是基于元素的出现频率来排序的,因此时间复杂度通常可以达到 O(n),但它对元素的范围(即最大值)有要求。

定义:

计数排序通过统计每个元素出现的次数来实现排序,然后根据这些统计结果重建排序后的数组。它是一种稳定的排序算法。

算法思想:

  1. 统计频率:首先通过遍历输入数组,统计每个元素出现的次数。
  2. 计算位置:然后,根据元素的计数信息,计算出每个元素在排序数组中的正确位置。
  3. 构建排序数组:根据位置将元素放到新的数组中,最终得到排序后的数组。
举个栗子

假设你有一个输入数组 [4, 2, 2, 8, 3, 3, 1],计数排序的过程会如下:

  1. 统计频率
    • 数字1出现1次,数字2出现2次,数字3出现2次,数字4出现1次,数字8出现1次。

    统计后得到的频率数组 count[]

    count[0] = 0
    count[1] = 1   (表示数字1出现1次)
    count[2] = 2   (表示数字2出现2次)
    count[3] = 2   (表示数字3出现2次)
    count[4] = 1   (表示数字4出现1次)
    count[5] = 0
    count[6] = 0
    count[7] = 0
    count[8] = 1   (表示数字8出现1次)

  2. 计算最后位置(即每个元素应该放置的位置)
    • count[1] = 1,表示数字1应该放置在排序数组的索引1的位置(即第二位)。
    • count[2] = 3,表示数字2应该放置在排序数组的索引3的位置(即第四位)。
    • count[3] = 5,表示数字3应该放置在排序数组的索引5的位置(即第六位)。
    • count[4] = 6,表示数字4应该放置在排序数组的索引6的位置(即第七位)。
    • count[8] = 7,表示数字8应该放置在排序数组的索引7的位置(即第八位)。
  3. 重建排序后的数组
    • 在重建排序数组时,我们从输入数组的最后一个元素开始,按照 count[] 中的信息将每个元素放置到它的最终位置。

    最终得到排序后的数组:[1, 2, 2, 3, 3, 4, 8]

为什么是“最后位置”?

当你在处理一个数组时,可能有重复的数字。例如数组 [2, 2]。在这种情况下,你希望这两个2保持它们在原数组中的相对顺序。为了保证这一点,在重建排序数组时,从数组的最后一个元素开始放置元素,以避免覆盖已经排序的元素。

所以当我们说“最后位置是索引1”,意味着数字1应该放置在排序后的数组的索引1的位置,并且在将所有元素放到新数组时,我们会按照这个逻辑逐步填充整个数组。

总结:计数排序是基于元素值的“计数”,因此它适合数据范围较小、且元素值是整数的情况

计数排序c++详解(看这一篇就够了)_第1张图片

代码:

#include 
#include 

using namespace std;

int arr[1000], output[1000], tot[1000];

void countingSort(int n) {
    if(n==0) 
    {
        return;
    }
    int maxVal=arr[0]; // 注意使用 arr[0] 来初始化最小值
    int minVal=arr[0];

    // 找到最大值和最小值
    for(int i=1;imaxVal) 
        {
            maxVal=arr[i];
        }
        if(arr[i]=0;i--) 
    {
        output[tot[arr[i]-minVal]-1]=arr[i];
        tot[arr[i]-minVal]--;
    }

    // 将排序后的数组复制回原数组
    for(int i=0;i

 

提醒:

  1. 适用范围:计数排序适用于元素范围较小且是整数的情况。如果数组的范围非常大,计数排序就可能变得低效,因为它需要创建一个大小为maxVal - minVal + 1的计数数组。
  2. 稳定性:计数排序是稳定的,即它不会改变相等元素的相对顺序。
  3. 空间消耗:虽然计数排序的时间复杂度是O(n + k),但它需要额外的空间O(k),即存储计数信息的空间,因此对于大范围的输入数据,可能会占用大量内存。
  4. 负数处理:计数排序默认假设所有输入都是非负整数。如果输入数组包含负数,必须对所有元素加上一个常数(比如-minVal)来转换成非负数。

何时使用计数排序:

  • 适用于数据范围(maxVal - minVal)较小的情况。
  • 排序的元素是整数,且重复元素较多时,计数排序特别高效。
  • 如果数据范围非常大(例如很大的数字范围或浮动范围),可以考虑使用其他排序算法,如快速排序或归并排序。

计数排序是一种高效的排序算法,但它有一定的限制,主要是对数据范围的要求较为严格。

你可能感兴趣的:(c++,算法,数据结构)