相较于冒泡排序,快速排序他们之间都是基于元素之间的比较来进行排序的。
而计数排序可以做到线性的时间复杂度,是由于它是利用数组下标来确定元素的正确位置的。
那么如何利用数组下标来确定元素位置呢?
给定一个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))