我有一个相当大的元素列表(数百个)。
我有一个可以接受或不接受元素的过滤器。
我想要满足过滤器的前100个元素。
到目前为止,我已经对结果进行了排序,然后选择了满足过滤器的前100名。这背后的基本原理是过滤器并不完全快。
但是现在,排序步骤比过滤步骤要长,所以我想以某种方式将它们组合起来。
是否有一种算法可以结合排序/过滤的关注点来获得满足过滤器的前100个结果,而不会产生排序所有元素的成本?
答案 0 :(得分:5)
我的直觉是从列表中选择前100个元素(比排序便宜得多,使用您最喜欢的QuickSelect变体)。通过过滤器运行它们,产生n
次成功和100-n
次失败。如果n < 100
,请从列表其余部分的顶部选择100-n
个元素重复:
k = 100
while (k > 0):
select top k from list and remove them
filter them, yielding n successes
k = k - n
一切顺利,这个时间与列表长度成正比,因为每个选择步骤都在那个时间运行,所需的选择步骤数取决于过滤器的成功率,但不是直接取决于过滤器的大小清单。
我希望这有一些不好的情况。如果几乎所有元素都没有通过过滤器,那么它比排序所有内容要慢得多,因为你最终会选择数千次。因此,如果它看起来很糟糕,你可能需要一些标准来挽救,然后再回到整个列表的排序。
它还存在这样的问题:它可能会在最后进行大量的小选择,因为如果过滤条件与排序标准无关,我们预计k会以指数方式衰减。所以你可以通过在每一步选择多于k个元素来改进它。比如说,k除以滤波器的预期成功率加上一个小常数。如果没有可用于预测它的领域知识,则基于过去表现的期望,以及通过实验选择的小常量来避免繁琐的大量步骤来找到最后几个元素。如果您在任何步骤中结束了更多通过过滤器的项目,而不是您仍在寻找的数字(即n> k),那么从当前成功的一批中选择前k,您就完成了。
由于QuickSelect为您提供了前k个而没有对这些k进行排序,如果您需要按顺序排在前100位,则需要进行最终的100个元素。
答案 1 :(得分:0)
我通过使用二叉树进行排序并在插入期间保持当前节点左侧的元素计数来解决这个问题。有关详细信息,请参阅http://pub.uni-bielefeld.de/publication/2305936(图4.4等)。
答案 2 :(得分:0)
如果我理解正确,你有两个选择:
选择100个元素 - 过滤器检查的N个操作。然后100(lg 100)进行排序。
排序然后选择100个元素 - 至少N(lg N)进行排序,然后选择。
第一个听起来更短,然后排序再选择。
答案 3 :(得分:0)
我可能先过滤,然后将其结果插入优先级队列。跟踪PQ中的项目数量,并在插入后,如果它大于您要保留的数字(在您的情况下为100),请弹出最小的项目并丢弃它。
答案 4 :(得分:0)
史蒂夫建议使用Quicksort是一个很好的建议。
1读入前1000个元素。
2对它们进行排序并选择第100个最大元素
3使用步骤2中的元素作为轴,在整个文件上运行Quicksort的一次传递
4选择Quicksort通道结果的上半部分以进行进一步处理。
Quicksort单程的上半部分保证至少有100个元素。假设前1000个合理地代表整个文件,那么在第4步你应该得到大约十分之一的原始元素。