使用静态容器找到序列中k个最大元素的最快算法是什么?
what is the fastest algorithm for finding the k-maximal elements of the sequence using stl-containers
我需要使用c++任意stl容器查找序列中k个最大元素的最快算法。我的想法是:使用列表或向量,对它们排序,得到前k个元素。在这种情况下,操作次数等于n*log(n)。N -元素的数目。但我认为这不是最好的。
使用std::partial_sort的方法可能是最好的答案。
还要注意 std::nth_element
, 刚好获得第n个位置的元素(并将序列划分为第n个元素之前的"小"和之后的"大")
所以,如果你真的对感兴趣,只是前k个元素 (没有特定的内部排序),那么 nth_element
绝对是biscuit
我认为最好的方法是使用一个向量来保存结果,并在你遍历输入时在其中建立一个堆。一旦堆大小达到k
,你就不再增加它了(只是保持从位置k-1
开始冒泡)。
当输入完成时,堆已经是一个答案(假设您没有被要求按顺序返回它们)。
如果是k > n/2
,那么最好存储那些从大小为n - k
的堆中冒出来的元素(但这假设您知道n
的元素数量,而不仅仅是k
)。
假设随机未排序的数据,我认为最快的是创建一个排序的链表,在原始容器上循环,对于每个元素,如果它大于结果向量中的最低值,将其钩入(在正确的排序位置)。如果列表现在包含超过k个元素,则删除最小的值。
最坏情况(排序的原始容器)是指O(k*n)
,最佳情况O(n)
。
使用QuickSelect,您可以使用wiki页面中描述的"智能"pivot选择在O(n)最坏情况下找到它们(未排序:它们是在算法引起的最终顺序中第k个元素之前的元素)。
你不能超过O(n)(因为你必须"触摸"所有元素以确保你选择的是第k个元素),所以这是你能达到的最好结果。
编辑:如果你不关心最大项的顺序,你可以使用nth_element
来划分一个向量,正如@sehe所指出的。这是O(n)
.
否则,如果你关心排序:
在数据向量上使用std::partial_sort
对第一个k
项进行排序。这将运行在O(n log k)
。
或者堆积您的数据并拉出k
项。这仍然是O(n log k)
,但我相信有更高的常数。
如果性能是一个问题,配置文件两种方法和使用更快的数据集。
遗憾的是,我找不到我为此编写的源代码,但是看看这个:
http://en.wikipedia.org/wiki/Radix_sort
我会使用std::make_heap
从数组或值向量构建堆,这将导致O(n)
时间。然后,您可以重复检查堆的顶部元素并将其弹出k
次(使用std::pop_heap
),这将导致O(k * log n)
时间。
总运行时复杂度将是O(k * log n)
,这比O (n * log k)
好,因为n大于k。正如你所问的,所有这些都已经在<algorithm>
中可用,所以实现起来非常容易。
可以在线性时间内通过使用选择算法来做到这一点,该算法在最坏情况下取O(n)
,然后遍历向量一次并精确地取至少与(n-k)阶统计量一样大的元素(并记录你取了多少元素,这样你就可以取k
而不是更多)。然而,Cppreference表示std::nth_element
平均花费线性时间,而不是最坏情况。我将用一种稍微慢一些但可能更简单的方法来解释如何使用堆。该解决方案在最坏情况下需要O(max(n,k*log(k)))
时间来提取大小为n
的向量的前k
个元素。
首先为所有n
元素创建一个max-heap,对于std::make_heap
,这需要O(n)时间。
我们现在想要从堆中提取k
的顶部元素,但是我们在这样做的时候必须聪明。如果我们提取最大元素k
次,那么每次将花费我们O(log(n))
,因此总共花费O(k*log(n))
,这没有达到我们的目标。
相反,我们不会碰这个n大小的堆,而是创建一个单独的最大堆,我称之为"等待堆"。这个等待堆只从原始堆的最大元素开始,为了获得顶部的k
元素,您需要重复以下过程k
次:从等待堆中提取顶部元素并将其两个后代添加到它中。等待堆的大小每一步增加1,因此它以k
为界。由于我们正在执行k
提取和2k
插入(假设您使用的是二进制堆),因此这将不会比3*k*log(k)
花费更多的时间。
- 从字符数组的元素中减去'a'是什么意思
- C++ 未初始化的本地(非全局)int 数组中的元素类型到底是什么?
- 在向量中查找大于 0(或通常为 k)的最小元素的最佳方法是什么?
- 通过作为指向 C++ 函数的指针传递来访问 std::array 元素的正确方法是什么?
- 找到对称矩阵的最大元素的最有效算法是什么
- 返回向量元素的 l 值的正确方法是什么?
- 按升序打印矢量的所有元素直到它为空而没有重复项的最有效方法是什么?
- 从长(且合理)稀疏向量中选择随机元素的最有效方法是什么?
- " ans += (a[i] - ans * r > 0); "是什么意思,其中 ans,r 是整数,a[i] 是数组元素?
- 在查找子集中元素和元素数量之间的二进制比较背后的逻辑是什么?
- 我如何找出3D容器的元素是什么类型
- 的每个元素是什么意思?
- 在 c 和 c++ 中,二维数组的元素是什么类型?
- 使用 CDT 从头文件中获取属性定义的节点元素是什么
- 在 typedef 中有三个元素是什么意思 C++.
- 数组在方括号中增加元素是什么意思
- 如何知道您输入到std::array中的最后一个元素是什么?
- 我读了map.erase(map.end());删除地图的最后一个元素。但是最后一个元素是什么?它是否基于元素的插入顺序?
- 向量中的第一个元素是什么
- 对象指针向量中的元素是什么