计数排序是一种平均时间复杂度为O(n+K)的排序算法,它假设输入元素都是0到K范围内的整数。为什么不能在未排序的数组中进行线性搜索最大值,将其等于K,然后应用计数排序呢?
maximum - minimum = O(n log n)
(即值的范围相当受限)的数组的情况下,计数排序确实是有意义的。如果不是这种情况,则标准的基于比较的排序算法甚至像基数排序这样的整数排序算法在渐近意义下更好。Θ(n^2)
:def generate_input(n):
array = []
for i := 1 to n:
array.append(i*i);
shuffle(array)
return array
f(n)
为计数排序在给定输入族上的运行时间。我们有f(n) = Θ(n + k) = Θ(n^2)
,因此我的说法是正确的。 - Niklas B.Ω(n + k)
和O(n + k)
,如果k
是O(n)
。因此,如Niklas所述,使用比数组长度大得多的数字违反了使Θ(n + k)
成立的前提条件。因此,如果数组中存在k = Θ(nˆ2)
,则时间复杂度变为Θ(n^2)
。 - JP Ventura你的问题标题是为什么不使用计数排序来处理大量数据?
计数排序是如何运作的呢?我们需要另一个数组(假设为b[])并将所有元素初始化为0。然后,如果给定数组中存在某个索引,我们就会增加该索引。接下来,我们从给定数组的下限到上限运行循环,并检查我所采取的数组(b[])的索引元素是否为0。如果不为零,则意味着该索引是给定数组的一个元素。
现在,如果这两个值(上限和下限)之间的差距非常高(例如10^9或更高),那么单个循环足以使我们的电脑崩溃 :)
std::map
来索引那个数组的元素。唯一的问题是要跟踪现有的元素,所以需要另一个std::set
。这是一种比较朴素的方法,如果你能告诉我更好的方法就好了。 - shauryachatsstd::set
和 std::map
的时间复杂度为 O(log n),这破坏了计数排序的优势。你不能使用哈希表,因为你需要按排序顺序迭代现有元素。但如果你能做到后者,你就不需要再排序了。 - Niklas B.f(n) ∈ O(g(n))
,那么意味着存在一个值C > 0
和n = N
,使得f(n) < C*g(n)
,其中C
和N
是常数。并没有说明C
的值,也没有说明不等式对于哪个n = N
成立。C
和N
的大小(或小)的定义因素,以便使不等式成立或不成立。删除这些成本是一种天真的假设,我在算法分析课程中曾经使用过。
语句“计数排序是O(n+k)
”实际上意味着,对于给定的C
、n > N
和n > K
,排序是多项式和线性的,其中C
、N
和K
是常数。因此,对于较小的输入,其他算法可能具有更好的性能,因为不等式仅在给定条件为真时才成立。