计数排序以牺牲一定量的空间来换取近乎于线性复杂度的运行时间,而且要求输入的元素必须是正整数。而且如果输入的元素中有超大的元素的时候,我们创建辅助list的时间可能就不能忽略不计了,这些也是这个算法的局限性所在,
通过创建长度为输入的最大值的辅助list,存储对应当前位序在输入list中有多少输入元素是小于等于当前位序的。
最后通过对辅助list进行稍微处理实现:当输入list中有相同元素的时候的排序
实现思路:
我们先用10个无序的随机数代表我们随机的输入listA
listC长度为listA中最大的元素
定义输出list: resultList,长度是10+1(为了方便理解和书写代码,稍后再解释)
先对listC进行第一步处理:在输入listA中每处理一个元素时对listC相应位序的元素加一
之后对listC进行第二部处理得到了对应当前位序在输入list中有多少输入元素是小于等于当前位序
最后从输入的没有排序的listA的最后一位开始,在结果list: resultList 中添加最后一位同时在listC中,将位序为当前输入值的 那个数减一(这个是为了让如果输入的没有排序的list中有相同值的时候可以直接将相同的第二个值放在对应的输出list的前一个位置上)
循环得出最后的结果list: resultList
注意因为只有n位数,而且我们对输出list的赋值是根据从1到10 的大小比较 所以输出list的长度是11 ,所以输出list的第一个位序为0的那个数一定是初始值0
所以第一位不输出
python代码实现如下
import numpy as np
import random
listA = [random.randint(1, 100) for i in range(10)] # 随机生成10个 100以内的数,listA
listC = [0 for x in range(max(listA)+1)]
resultList = [0 for x in range(len(listA)+1)]
def countSort(listA, listC):
for currentNum in listA:
listC[currentNum] += 1
pass
# 这步操作在listC中得到了对应当前位序有多少输入是小于等于当前位序
for currentIndex in range(1,len(listC)):
listC[currentIndex] = listC[currentIndex]+listC[currentIndex-1]
print('辅助listC得到了对应当前位序有多少输入是小于等于当前位序\n',listC)
print('从输入的没有排序的list的最后一位开始,在结果list中添加最后一位同时在listC中将位序为当前输入值的 那个数减一,这个是为了让如果输入的没有排序的list中有相同值的时候可以直接将相同的第二个值放在对应的输出list的前一个位置上')
for currentIndex in range(len(listA)-1,-1,-1):
resultList[listC[listA[currentIndex]]] = listA[currentIndex]
listC[listA[currentIndex]] = listC[listA[currentIndex]]-1
print('展示运行排序之后的辅助函数listC\n',listC)
print('初始的模拟输入的无序listA:\n',listA)
# 计数排序
countSort(listA, listC)
print('注意因为只有n位数,而且我们对输出list的赋值是根据从1到10 的大小比较 所以输出list的长度是11 ,所以输出list的第一个位序为0的那个数一定是初始值0,')
print('所以第一位不输出')
resultList = resultList[1:]
print(resultList)
运行结果:
初始的模拟输入的无序listA:
[91, 68, 16, 80, 81, 54, 42, 97, 76, 91]
辅助listC得到了对应当前位序有多少输入是小于等于当前位序
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 10]
从输入的没有排序的list的最后一位开始,在结果list中添加最后一位同时在listC中将位序为当前输入值的 那个数减一,这个是为了让如果输入的没有排序的list中有相同值的时候可以直接将相同的第二个值放在对应的输出list的前一个位置上
展示运行排序之后的辅助函数listC
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9]
注意因为只有n位数,而且我们对输出list的赋值是根据从1到10 的大小比较 所以输出list的长度是11 ,所以输出list的第一个位序为0的那个数一定是初始值0,
所以第一位不输出
[16, 42, 54, 68, 76, 80, 81, 91, 91, 97]
Process finished with exit code 0
最后我们可以通过循环的次数看出我们对长度为输入元素的最大值的list进行了两次循环,对输入的数组进行了一次循环,设输入元素的最大值为k,输入的数组长度为n
所以时间复杂度是Θ(k+n)
可见输入的最大元素对算法性能的影响很大。