一、计数排序简介
计数排序(Counting Sort)是一种不比较数据大小的排序算法,是一种牺牲空间换取时间的排序算法。计数排序适合数据量大且数据范围小的数据排序,如对人的年龄进行排序,对考试成绩进行排序等。计数排序先找到待排序列表中的最大值 k,开辟一个长度为 k+1 的计数列表,计数列表中的所有初始值都为 0。走访待排序列表,如果走访到的元素值为 i,则计数列表中索引 i 的值加1,走访完整个待排序列表,就可以统计出待排序列表中每个值的数量。然后创建一个新列表,根据计数列表中统计的数量,依次在新列表中添加对应数量的 i ,得到排好序的列表。二、计数排序原理
计数排序的原理如下:1. 找到待排序列表中的最大值 k,开辟一个长度为 k+1 的计数列表,计数列表中的值都为 0。2. 走访待排序列表,如果走访到的元素值为 i,则计数列表中索引 i 的值加1。3. 走访完整个待排序列表,计数列表中索引 i 的值 j 表示 i 的个数为 j,统计出待排序列表中每个值的数量。4. 创建一个新列表,遍历计数列表,依次在新列表中添加 j 个 i,新列表就是排好序后的列表,整个过程没有比较待排序列表中的数据大小。以列表 [5, 7, 3, 7, 2, 3, 2, 5, 9, 5, 7, 6] 进行升序排列为例。列表的初始状态如下图。 1. 待排序列表中的最大值为9,所以开辟一个长度为10的计数列表,索引为0~9,值全为0。 2. 走访待排序列表,如果走访到的元素值为 i,则计数列表中索引 i 的值加1。第一个元素值为5,计数列表中索引5的值加1,从0变为1。 3. 第二个元素值为7,计数列表中索引7的值加1,从0变为1。 4. 第三个元素值为3,计数列表中索引3的值加1,从0变为1。 5. 第四个元素值为7,计数列表中索引7的值加1,从1变为2。 6. 重复走访完整个待排序列表,所有元素的个数都统计到了计数列表中。 7. 创建一个新列表,遍历计数列表,依次在新列表中添加对应数量的元素。0和1都是0个,不需要添加,2有两个,在新列表中添加两个2。添加后计数列表中减掉对应的数量。 8. 3有两个,继续在新列表中添加两个3。添加后计数列表中减掉对应的数量。 9. 遍历整个计数列表,添加完所有的数据,新列表就是排序完成后的列表。排序结果如下图。三、Python实现计数排序
# coding=utf-8def counting_sort(array): if len(array) < 2: return array max_num = max(array) count = [0] * (max_num + 1) for num in array: count[num] += 1 new_array = list() for i in range(len(count)): for j in range(count[i]): new_array.append(i) return new_arrayif __name__ == '__main__': array = [5, 7, 3, 7, 2, 3, 2, 5, 9, 5, 7, 6] print(counting_sort(array))
运行结果:
[2, 2, 3, 3, 5, 5, 5, 6, 7, 7, 7, 9]
代码中,使用Python内置函数max()求出待排序列表中的最大值。然后根据上面分析的排序原理,进行计数,再将数据添加到新列表中。i 表示计数列表的索引,也表示待排序列表中值为 i 的元素,j 表示值为 i 的元素有 j 个。
四、计数排序的时间复杂度和稳定性
1. 时间复杂度在计数排序中,需要走访待排序列表中的每一个元素,进行计数,列表长度为 n ,然后需要遍历计数列表,添加数据到新列表中,计数列表长度为 k+1 ,时间复杂度为 T(n)=n+k+1,再乘计数和添加数据的步骤数(常数,不影响大O记法),所以计数排序的时间复杂度为 O(n+k) 。2. 稳定性根据计数排序的应用场景,待排序列表中有很多值相等的元素。不过,计数排序没有比较待排序列表中的数据大小,也没有进行位置交换,相等数据的相对次序是保持不变的。所以计数排序是一种稳定的排序算法。