计数排序原理,局限加python实现

本文深入解析计数排序算法,探讨其工作原理、实现步骤及时间复杂度。计数排序利用额外空间实现近似线性时间复杂度的排序,特别适用于正整数集合。文章详细描述了如何创建辅助列表,跟踪每个位序的元素数量,以及如何处理重复元素,确保正确排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

计数排序以牺牲一定量的空间来换取近乎于线性复杂度的运行时间,而且要求输入的元素必须是正整数。而且如果输入的元素中有超大的元素的时候,我们创建辅助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)
可见输入的最大元素对算法性能的影响很大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值