用于将数据与文件系统路径相关联的高效数据结构?

时间:2012-11-05 10:43:37

标签: c# data-structures dictionary path trie

我需要在内存中保留一些关于可能大量文件和目录的数据(通常高达几十万)。显而易见的方法是使用以路径为键的Dictionary<string, Something>,但这有两个问题:

  • 许多文件的路径都有很大的共同点,因此存储每个文件的完整路径可能会浪费内存
  • 我需要能够快速访问有关目录所有后代的数据;使用字典,唯一的方法是测试每个键并检查它是否以指定的路径开始,这是非常低效的

此问题似乎是使用前缀树(或trie)的良好候选者,路径段为“字符”。我试图实现它,并且前缀查找的性能也不错(大约比字典快4倍),但它有两个问题:

  • 内存消耗不会减少,可能是因为每个节点的子代表列表的开销
  • 施工时间比使用字典要差得多(填充集合的速度大约慢4倍)

我确定它一定是一个非常常见的问题,所以也许有一些我不知道的众所周知的解决方案?

2 个答案:

答案 0 :(得分:2)

只是一些通用的想法:

首先,Patricia trie可能是提高尝试内存消耗的最着名的方法 - 它压缩了所有节点将一个子节点放入一个节点的路径,并沿着路径连接字符。还有一个版本,您可以将数据视为二进制数字序列,其优点是您总是最多有2个子节点,并且它也更容易实现。

其次,内存消耗实际上取决于您如何存储给定节点的子节点 - 您是否维护了256个节点的数组?这通常是直接查找的最有效方式,但是如果需要遍历所有子节点,它也会消耗最多的内存并且速度很慢。其他选择是:

  • 存储一对数组(letter, child node) - 这可能是内存效率最高的,因为它只存储您真正关心的对象,并且在迭代所有子节点方面也具有良好的性能。但是,您必须检查所有对直接查找 - 通常距离根更远,但可能是根目录附近的问题。

  • 在将字母映射到子节点的每个节点中存储某种字典。这在性能方面是最平衡的 - 它为所有操作提供了相当好的速度,并且具有一定的内存效率。

此外,如果你预先构建整个集合然后只是查询它,有一种方法可以存储基于Tarjan tables的子链接,这可能会增加构造时间,但会节省内存和查询时间过了。

答案 1 :(得分:-1)

前缀树怎么样的方法。即如果你想存储

/root/x
/root/a/b
/root/a/c
/root/a/d
/root/a/e
/root/a/c/e
/root/a/c/f
Here is how your tree will look like. 
                       root
                     /    \
                    x   __ a __ 
                       /  / \   \ 
                     b   c    d   e
                        / \
                       e   f

它将节省空间,因为每个目录名称只会存储一次。 搜索和插入也将是O(log(n))