【问题标题】:Efficient data structure for a list of index sets索引集列表的高效数据结构
【发布时间】:2013-01-06 17:32:48
【问题描述】:

我试图举例说明:

想象一个编号元素的列表 E = [elem0, elem1, elem2, ...]。

一个索引集现在可以是 {42, 66, 128} 引用 E 中的元素。这个集合中的顺序并不重要,所以 {42, 66, 128} == {66, 128, 42},但是每个元素在任何给定的索引集中最多出现一次(因此它是一个实际的集合)。

我现在想要的是一个节省空间的数据结构,它给了我另一个有序列表 M,其中包含引用 E 中元素的索引集。M 中的每个索引集只会出现一次(因此 M 在这方面是一个集合)但是 M 本身必须是可索引的(因此 M 在这个意义上是一个 List ,因此精确的索引并不重要)。如有必要,可以强制索引集包含相同数量的元素。

例如,M 可能如下所示:

0: {42, 66, 128}
1: {42, 66, 9999}
2: {1, 66, 9999}

我现在可以执行以下操作:

for(i in M[2]) { element = E[i]; /* do something with E[1],E[66],and E[9999] */ }

您可能知道这是怎么回事:您现在可能有另一个映射 M2,它是指向 M 的有序集合列表,最终指向 E 中的元素。

正如你在这个例子中看到的那样,索引集可以相对相似(M[0] 和 M[1] 共享前两个条目,M[1] 和 M[2] 共享后两个),这让我认为必须有比使用集合数组的天真方式更有效的方法。但是,我可能无法提出保证良好“共享”的索引条目的良好全局排序。

我可以想到任何东西,从将 M 表示为一棵树(其中 M 的索引来自深度优先搜索排序或其他东西)到联合查找结构的哈希映射(虽然不知道它是如何工作的:)

非常欢迎指向任何教科书数据结构的指针(数据库世界里有什么东西吗?)但如果您提出“自制”解决方案或只是随机的想法,我也很感激。

空间效率对我来说很重要,因为 E 可能包含数千甚至几百万个元素,(某些)索引集可能很大,至少一些索引集之间的相似性应该很大,并且可能存在多层映射。

非常感谢!

【问题讨论】:

  • 信息太多。我无法理解 M 是如何生成的。请解释 1 和 9999 是从哪里拍摄的?
  • 这只是一个例子,数字并不重要。 M 的条目 2 = {1, 66, 9999} 仅引用元素 E[1]、E[66]、E[9999]。如果你需要一些具体的东西,想想 E 包含你的 10.000 个 facebook 朋友,M[2] 包含所有在 3 月结识的朋友的索引(0=1 月,1=2 月,2=3 月)。
  • 对我来说再次不是很清楚。 E 是指定用户的好友还是它的全局用户列表? M[X] 是“在 X 中结识的朋友”,请更好地澄清这部分,因为我不明白为什么会有重复,因为我理解这是一个主要问题,需要对其进行优化。这些用户的所有组合都与指定用户结为好友或结为好友?

标签: algorithm data-structures


【解决方案1】:

您可以合并 M 中的所有数字并删除重复项并将其命名为 UniqueM。

所有 M[X] 集合都转换为位掩码。例如 int 值可以存储 32 个数字(为了支持无限计数,您应该存储整数数组,如果数组大小总共为 10,我们可以存储 320 个不同的元素)。 long 类型可以存储 64 位。

E: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

M[0]: {6, 8, 1}
M[1]: {2, 8, 1}
M[2]: {6, 8, 5}

将转换为:

UniqueM: {6, 8, 1, 2, 5}
M[0]: 11100 {this is 7}
M[1]: 01110 {this is 14}
M[2]: 11001 {this is 19}

注意: 您也可以结合 my 和 ring0 方法,而不是重新排列 E 创建新的 UniqueM 并在其中使用间隔。

【讨论】:

  • 非常感谢,对于并非 E 中的所有元素都出现在 M 中的情况(即 |M|
【解决方案2】:

要击败索引将非常困难。您可以通过使用正确的数据类型来节省一些空间(例如,在 gnu C 中,short 如果 E 中的元素少于 64k,int 如果

另外,

既然你说 E 中的顺序并不重要,你可以对 E 进行排序,使其最大化连续元素以尽可能匹配 Ms。

例如,

E: { 1,2,3,4,5,6,7,8 }

0: {1,3,5,7}
1: {1,3,5,8}
2: {3,5,7,8}

通过重新排列E

E: { 1,3,5,7,8,2,4,6 }

使用 E 索引,而不是值,您可以根据 E 的子集定义 Ms,并给出索引

0: {0-3}     // E[0]: 1, E[1]: 3, E[2]: 5, E[3]: 7 etc...
1: {0-2,4}
2: {1-3,4}

这边

  • 您使用索引而不是原始数字(索引通常更小,没有负数..)
  • Ms 由子集组成,0-3 表示 0,1,2,3,

困难的部分是使算法重新排列 E 以便最大化子集大小 - 最小化 Ms 大小。

E重排算法建议

  • 对所有女士排序
  • 处理所有女士:

构建地图的算法,它为元素“x”提供其邻居列表“y”以及,“y”在“x”之后的次数

Map map (x,y) -> z
for m in Ms
  for e,f in m // e and f are consecutive elements
    if ( ! map(e,f)) map(e,f) = 1
    else map(e,f)++
  rof
rof

重新排列E

ER = {}                 // E rearranged
Map mas = sort_map(map) // mas(x) -> list(y) where 'y' are sorted desc based on 'z' 
e = get_min_elem(mas)   // init with lowest element (regardless its 'z' scores)


while (mas has elements) 
  ER += e        // add element e to ER
  f = mas(e)[0]  // get most likely neighbor of e (in f), ie first in the list
  if (empty(mas(e))
    e = get_min_elem(mas) // Get next lowest remaining value
  else
    delete mas(e)[0]  // set next e neighbour in line
    e = f
  fi
elihw

算法(地图)应该是O(n*m)空间,E中有n个元素,所有Ms中有m个元素。

【讨论】:

  • 好点。谢谢。我喜欢尽可能使用索引间隔的想法。正如你所说,魔法就在于如何重新排列 E 我不确定这是否可行(在合理的时间内)。但我肯定会更多地研究这个方向。
  • 添加了一个建议的算法 - 希望它足够清楚:-)
【解决方案3】:

可以使用位数组。它们是元素数组a[i],如果i 在集合中,则为1,如果i 不在集合中,则为0。因此,即使每个集合包含少数成员或不包含成员,每个集合也将完全占据 size(E) 位。空间效率不高,但如果你用一些压缩算法压缩这个数组,它的大小会小得多(可能达到最终熵限制)。因此,您可以尝试动态马尔可夫编码器或 RLE 或 Huffman 组,然后选择最适合您的一种。然后,迭代过程可以包括动态解压缩,然后线性扫描1 位。对于 looong 0 运行,您可以修改解压缩算法以检测此类情况(RLE 是最简单的情况)。

如果您发现集合的差异较小,您可以存储集合AA xor B 而不是AB,以节省公共部分的空间。在这种情况下,要遍历B,您必须解压缩AA xor B,然后再解压缩xor

【讨论】:

  • 有趣...我想到了位集,但并没有真正考虑压缩它们。我将尝试压缩对我的特定位字段的效果,然后再回复您。另一个想法可能是使用二元决策图 (BDD) 作为位集压缩的一种形式。
【解决方案4】:

另一个有用的解决方案:

E: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

M[0]: {1, 2, 3, 4, 5, 10, 14, 15}
M[1]: {1, 2, 3, 4, 5, 11, 14, 15}
M[2]: {1, 2, 3, 4, 5, 12, 13}

缓存常用物品

Cache[1] = {1, 2, 3, 4, 5}
Cache[2] = {14, 15}
Cache[3] = {-2, 7, 8, 9} //Not used just example.

M[0]: {-1, 10, -2}
M[1]: {-1, 11, -2}
M[2]: {-1, 12, 13}

将指向缓存列表的链接标记为负数。

【讨论】:

    猜你喜欢
    • 2011-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-21
    • 1970-01-01
    • 1970-01-01
    • 2017-01-07
    • 1970-01-01
    相关资源
    最近更新 更多