比快排还快(网安2312陈卓)

有这样一种排序问题:任意给定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的存入数组
建好后输出即为排序后的序列

感想:对于生活中的每一类问题,并不一定都只能采用固定的为人熟知的算法,算法始终是灵活的,人为的,只要我们细心思考,总会有不一样的思维和解题思路,说不定最终所得到的算法就是该类问题的最优解而不是那些面对大类问题所固有的算法,多加尝试,终会有结果。

posted @ 2025-04-04 11:16  取名字比写博客还难  阅读(6)  评论(0)    收藏  举报