有这样一种排序问题:任意给定k个(k<10w)不重复的数字,每个数字的取值范围为[1,10w]。希望设计出一种排序算法对这10万个数字进行排序,时间复杂度尽可能小。
第一时间我们可能会想使用快速排序,因为快排的时间复杂度只有O(nlogn)。但有没有比O(nlogn)更快的排序方法呢?你可能会有疑问:O(nlogn)已经是最快的排序算法了,怎么可能还有更快的排序方法?我们知道对于寻常的排序算法,无论是归并排序,冒泡排序还是快速排序等等,都是基于元素之间的比较来进行排序的,但对于题目中的这类问题,我们可以借助数组进行很好的排序,这种排序算法不是基于元素比较,而是利用数组下标来确定元素的正确位置。(灵感来源于统计)
以10个随机数为例:在刚才的题目里,随即整数的取值范围是从0到10,那么这些整数的值肯定是在0到10这11个数里面。于是我们可以建立一个长度为11的数组,数组下标从0到10,元素初始值全为0
先假设10个随机整数的值是:9, 3, 5, 4, 6,12, 2, 7, 11,1
让我们先遍历这个无序的随机数组,每一个整数按照其值对号入座,对应数组下标的元素进行加1操作。
比如第一个整数是9,那么数组下标为9的元素加1
第二个整数是3,那么数组下标为3的元素加1
继续遍历数列并修改数组......
最终,数列遍历完毕时,数组的状态如下:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 |
数组中的每一个为1的值,代表该数是代排数中的其中一个
有了这个统计结果,排序就很简单了,直接遍历数组,输出数组元素的下标值:
1,2,3,4,5,6,7,9,11,12
显然,这个输出的数列已经是有序的了。
过程总结:
1.初始化计数数组:创建一个长度为10万的数组count,所有元素初始化为0。
2.计数:遍历给定的k个数字,对于每个数字,将count数组中对应索引的值增加1。
3.重建数组:创建一个新的数组来存储排序后的结果。再次遍历count数组,对于每个非零元素,将其索引添加到结果数组中,重复次数等于该元素的值。
时间复杂度:由于我们只需要遍历两次数组(一次用于计数,一次用于重建数组),时间复杂度为O(n + m),其中n是待排序数字的数量(在这个问题中是10万),m是给定数字的数量(在这个问题中是1)。
空间复杂度:我们需要一个长度为10万的计数数组和一个长度为k的结果数组,所以空间复杂度为O(n)。
伪代码:
# 初始化计数数组,长度为k,所有元素为0
int count[100000]={0};
# 计数阶段
输入数据并以此为下标在数组中对应值更改为1
# 重建数组阶段
新建一个数组,采用for循环将每个为1的存入数组
建好后输出即为排序后的序列
标签:10,遍历,陈卓,复杂度,元素,比快,数组,排序,参与者
From: https://www.cnblogs.com/cm58/p/18247368