Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm top-k选择/合并_Algorithm_Database Design - Fatal编程技术网

Algorithm top-k选择/合并

Algorithm top-k选择/合并,algorithm,database-design,Algorithm,Database Design,我有n个排序列表(5

我有n个排序列表(5 k=2的示例:

top2 (L1: [ 'a': 10, 'b': 4, 'c':3 ]) = ['a':10 'b':4]
top2 (L2: [ 'c': 5, 'b': 2, 'a':0 ]) = ['c':5 'b':2]
更有趣的是,当我想要所有排序列表中的前k名组合时

top2(L1+L2) = ['a':10, 'c':8]
仅将单个列表中的前k项组合在一起不一定会得到正确的结果:

top2(top2(L1)+top2(L2)) = ['a':10, 'b':6]
目标是减少所需的空间,并保持已排序的列表较小

top2(topX(L1)+topX(L2)) = ['a':10, 'c':8]
问题是,是否有一种算法来计算组合的top k,该k具有正确的顺序,同时在某个位置切断列表的长尾。如果有:如何找到极限X,在哪里可以安全地切割

注意:正确的计数并不重要。只有命令是正确的

top2(magic([L1,L2])) = ['a', 'c']

如果我对你的问题理解正确,正确的输出是前10项,而不管每个项来自哪个列表。如果这是正确的,那么从每个列表中的前10个项目开始将允许您生成正确的输出(如果您只希望在输出中有唯一的项目,但输入可能包含重复项,那么您需要在每个列表中有10个唯一的项目)

在最极端的情况下,所有顶部项目都来自一个列表,而忽略其他列表中的所有项目。在这种情况下,一个列表中有10个项目就足以产生正确的结果

  • 将索引与n个列表中的每个列表相关联。在每种情况下,将其设置为指向第一个元素
  • 创建列表列表,并按索引元素对其排序
  • 列表列表中顶部列表上的索引项是第一个元素
  • 增加最顶层列表的索引,并从列表列表中删除该列表,然后根据其索引元素的新值重新插入该列表
  • 列表列表中顶部列表上的索引项是下一个元素
  • 转到4并重复,直到完成

  • 您没有指定有多少个列表。如果n很小,那么步骤4可以非常简单地完成(只需重新排序列表)。随着n的增长,您可能需要考虑更有效的方法来使用几乎已排序的列表。

    总的来说,我认为您遇到了麻烦。想象一下下面的列表:

    ['a':100, 'b':99, ...]
    ['c':90, 'd':89, ..., 'b':2]
    
    你有k=1(也就是说,你只想要最上面的一个)“b”是正确的答案,但你需要一直往下看第二个列表的末尾,才能意识到“b”胜过“a”

    编辑:

    如果你有正确的分布(长的、低计数的尾巴),你可能会做得更好。让我们暂时保持k=1,让我们的生活更轻松

    基本算法是保存一个到目前为止看到的密钥及其相关总数的哈希图。浏览列表,处理元素并更新地图

    关键的观察结果是,一个键最多可以通过每个列表当前处理点的计数总和(称为总和S)获得计数。因此,在每一步中,您都可以从哈希映射中删除总数比当前最大计数元素少S以上的任何键。(我不确定需要删减什么样的数据结构,因为需要查找给定计数范围的键—可能是优先级队列?)


    当哈希映射中只有一个元素,且其计数至少为S时,可以停止处理列表并返回该元素作为答案。如果您的计数分布很好,那么这个提前退出实际上可能会触发,这样您就不必处理所有的列表。

    我不知道两个列表中是否出现“a”,它们的计数必须合并。下面是一个新的内存高效算法:

    (新)算法:

  • (重新)按ID对每个列表进行排序(而不是按计数)。要释放内存,可以将列表写回磁盘。只需要足够的内存来存储最长的列表
  • 获取下一个最低的未处理ID,并查找所有列表的总计数
  • 将ID插入k个节点的集合中。使用总计数作为节点的优先级(而不是ID)。如果插入的节点超过k个,此优先级队列将丢弃最低的节点
  • 转至步骤2,直到耗尽所有ID
  • 分析:此算法只需使用O(k)个额外内存来存储最小堆即可实现。为了实现这一点,它做了几个权衡:

  • 列表按就地ID排序;按计数的原始订单丢失。否则,需要O(U)额外的内存来创建ID为:total_count元组的主列表,其中U是唯一ID的数量
  • 通过检查每个列表的第一个元组,在O(n)时间内找到下一个最低的ID。这将重复U次,其中U是唯一ID的数量。这可以通过使用最小堆来跟踪下一个最低的ID来改进。这需要O(n)个额外的内存(在所有情况下可能不会更快)

  • 注意:此算法假定可以快速比较ID。字符串比较并不简单。我建议将字符串ID散列为整数。它们不必是唯一的散列,但必须检查冲突,以便正确排序/比较所有ID。当然,这会增加内存/时间复杂性。

    此算法使用O(U)内存,其中U是唯一键的数量。我怀疑能否达到较低的内存界限,因为在所有键相加之前,无法判断哪些键可以丢弃

  • 制作一个(键:total_count)元组的主列表。只需一次一项地遍历每个列表,记录每个键被看到的次数
  • 在主列表中使用任何不使用额外内存的内容。一个简单的解决方案是对列表进行适当排序

  • 完美的解决方案要求所有元组至少检查一次

    然而,不需要检验就可以接近完美的解决方案