计数排序是一种简单高效的排序算法,它属于非比较型排序算法,特别适用于整数排序,尤其是当数据的取值范围不大时。相比于冒泡排序、选择排序等基于比较的排序算法,计数排序通过统计元素出现的次数来确定元素的最终位置,从而实现排序,时间复杂度可以达到线性级别(O(n + k),其中n是待排序元素的个数,k是数据的取值范围)。

基本思路

  1. 确定数据范围:首先找出待排序数组中的最小值和最大值,这样我们就能确定需要统计的元素范围,避免创建过大的计数数组。
  2. 统计元素出现次数:创建一个计数数组,长度为(最大值 - 最小值 + 1),用于记录每个元素出现的次数。
  3. 构建排序结果:根据计数数组的统计结果,从最小值开始,依次输出每个元素,输出的次数等于该元素在计数数组中记录的次数。

示例演示

以数组 [4, 2, 2, 8, 3, 3, 1] 为例,演示计数排序的过程:

  1. 确定数据范围:数组中的最小值是 1,最大值是 8,因此数据范围是 1~8,计数数组长度为 8 - 1 + 1 = 8
  2. 统计元素次数:遍历原数组,统计每个元素出现的次数:
    - 元素 1 出现 1 次
    - 元素 2 出现 2 次
    - 元素 3 出现 2 次
    - 元素 4 出现 1 次
    - 元素 8 出现 1 次
    - 其他元素(5、6、7)出现 0 次
    因此计数数组为 [1, 2, 2, 1, 0, 0, 0, 1](索引 0~7 分别对应 1~8 的次数)。
  3. 构建排序结果:从最小值 1 开始,依次输出计数数组中每个元素的次数:
    - 输出 1 一次 → [1]
    - 输出 2 两次 → [1, 2, 2]
    - 输出 3 两次 → [1, 2, 2, 3, 3]
    - 输出 4 一次 → [1, 2, 2, 3, 3, 4]
    - 输出 8 一次 → [1, 2, 2, 3, 3, 4, 8]

Python 实现

def counting_sort(arr):
    # 处理空数组或单元素数组(无需排序)
    if not arr:
        return []
    if len(arr) == 1:
        return arr

    # 步骤1:确定最小值和最大值
    min_val = min(arr)
    max_val = max(arr)

    # 步骤2:创建计数数组(长度为最大值-最小值+1,初始化为0)
    count_size = max_val - min_val + 1
    count = [0] * count_size

    # 步骤3:统计每个元素出现的次数
    for num in arr:
        # 计算当前元素在计数数组中的索引(元素值 - 最小值)
        index = num - min_val
        count[index] += 1  # 对应元素出现次数+1

    # 步骤4:根据计数数组生成排序结果
    sorted_arr = []
    for i in range(count_size):
        # 当前元素值 = 最小值 + 计数数组索引
        num = min_val + i
        # 将当前元素重复 count[i] 次添加到结果数组
        sorted_arr.extend([num] * count[i])

    return sorted_arr

代码解释

  • 边界处理:如果输入数组为空或只有一个元素,直接返回原数组(无需排序)。
  • 数据范围确定:通过 min()max() 获取数组的最小值和最大值,避免创建过大的计数数组。
  • 计数数组构建:长度为 max_val - min_val + 1,确保覆盖所有可能的元素。
  • 统计次数:遍历原数组,对每个元素计算其在计数数组中的索引(num - min_val),并累加次数。
  • 生成结果:从最小值开始,按顺序输出每个元素,输出次数由计数数组中对应位置的值决定。

适用场景与特点

  • 适用场景:数据为整数且取值范围较小(如考试分数、年龄等),或存在大量重复元素时。
  • 稳定性:计数排序是稳定排序(相等元素的相对顺序在排序后保持不变),因为重复元素会按原顺序依次输出。
  • 内存占用:若数据范围过大(如最大值远大于最小值),计数数组会占用较多内存,此时可能不适用。

测试示例

# 测试用例1:基础整数数组
arr1 = [4, 2, 2, 8, 3, 3, 1]
print(counting_sort(arr1))  # 输出:[1, 2, 2, 3, 3, 4, 8]

# 测试用例2:包含负数的数组
arr2 = [-3, 1, 2, -3, 0]
print(counting_sort(arr2))  # 输出:[-3, -3, 0, 1, 2]

通过上述步骤,计数排序能高效地对整数数组进行排序,尤其适合数据范围小且重复元素多的场景。

小夜