详解计数排序

相较于冒泡排序,快速排序他们之间都是基于元素之间的比较来进行排序的。
而计数排序可以做到线性的时间复杂度,是由于它是利用数组下标来确定元素的正确位置的。
那么如何利用数组下标来确定元素位置呢?
给定一个20个整数的无序数列,取值范围是0-10,所以就可以创建一个长度为11的数组。然后开始遍历这个无序的随机数列,每一整数按照其值对号入座,这时在这个创建的数组上对应其值的下标的元素加1.
有点绕,就是假设20个整数中有3个9,那么我们就找到那3个9,并在对应数组的索引的元素上加1.所以创建的数组元素的索引9上的元素是3。
最终,当这个无序数列遍历完毕之后,该数组中每一个下标位置的值代表数列中对应整数出现的次数。
有了这个统计就可以直接遍历数组,输出数组下标的值(索引),元素的值是几,就输出几次。
这里需要编写的操作主要有

1.确定数组的长度

max_value = array[0]
    for i in range(1, len(array)):
        if array[i] > max_value:
            max_value = array[i]

先假设列表中第一个元素最大,然后遍历列表,比较找出最大的那个值
然后根据这个值创建数组

count_array = [0] * (max_value+1)

2.遍历数列,填充统计数组(这也是最重要的一步)

    for i in range(0, len(array)):
        count_array[array[i]] += 1 

这里用数列的值当做索引,然后再加1.若一个数列中相同的值很多,那么就会继续加1

3.遍历统计数组,输出结果

sorted_array = []
    for i in range(0, len(count_array)):
        for j in range(0, count_array[i]):
            sorted_array.append(i)
    return sorted_array

这里创建个数组来接收排序后的列表,利用count_array[i]这个代表无序数列中具体的元素有几个来进行for循环。可以精确的输出元素有几个。

这样输出该数组就达到了计数排序的目的了

但这里还有些优化的点。比如,
1.我们无法确定输出相同值元素原本在无序数列中的顺序,这就造成这是个不稳定排序
2.创建数组的长度是根据无序数列中最大元素确定的,这个其实是不可取的。如:99,100,22,33,4,5.这6个元素组成的无序数列,按最大元素就要创建100个下标的数组,这太浪费空间了。
对于第1点优化的点可以采用从统计数组的第二个元素开始,每个元素都加上前面所有元素之和。
对于第2点优化可以采用max_value-min_value+1得出数组的长度,但这其实还是比较浪费空间(这里其实可以去看看堆排序,他在创建数组空间上做的比较好)

完整代码(优化的计数排序)

# 计数排序的优化属于稳定版本的计数排序,可以返回相同数据的顺序先后;可用在学生成绩排名
def count_sort_v2(array=[]):
    # 1.得到数列的最大值最小值,并算出差值d
    max_value = array[0]
    min_value = array[0]
    for i in range(1, len(array)):
        if array[i] > max_value:
            max_value = array[i]
        if array[i] < min_value:
            min_value = array[i]
    d = max_value - min_value
    # 2.创建统计数组并统计对应元素个数
    count_array = [0] * (d+1)
    for i in range(0, len(array)):
        count_array[array[i]-min_value] += 1 # 这里创建的统计数组全为0
    # 3.统计数组做变形,后面的元素等于前面的元素之和
    for i in range(1, len(count_array)):
        count_array[i] += count_array[i-1] # 这算个列表的技巧,后面索引的值是前面索引值的和
    # 4.倒序遍历原始数列,从统计数组找到正确位置,输出到结果数组
    sorted_array = [0] * len(array)
    for i in range(len(array)-1, -1, -1): # array[i]是原数组的值
        # 这里减1是为啥,因为数组是从0开始的
        sorted_array[count_array[array[i]-min_value]-1] = array[i] # count_array[array[i]-min_value]填充统计数组的值,min_value是统计数组的开头
        count_array[array[i] - min_value] -= 1
    return sorted_array # 返回的是重新创建的数组,这里创建了2个数组


my_array = list([4, 4, 6, 5, 3, 2, 8, 1, 7, 5, 6, 0, 10])
print(count_sort(my_array))
my_array = list([95, 94, 91, 120, 90, 99, 93, 91, 92])
print(count_sort_v2(my_array))

努力拼搏吧,不要害怕,不要去规划,不要迷茫。但你一定要在路上一直的走下去,尽管可能停滞不前,但也要走。
原文地址:https://www.cnblogs.com/wkhzwmr/p/15344768.html