1

首先,这可能是一个 XY 问题,对此感到抱歉。

我正在从文件加载文件表并将其放入内存文件树中。树中的节点代表树中的目录/文件。目前,我每个节点使用两个数据结构,这会导致明显的加载时间,因为插入到集合中,并且由于复制字符串数据和引用每个节点两次而导致更高的内存使用。树只加载一次,之后不会发生变异。

每个节点都有一个用于访问已排序子节点的列表和一个用于按名称访问子节点的字典。出于性能原因,该列表被延迟排序。SortedDictionary 不符合我的使用要求,因为我需要将有子节点的节点排在没有子节点的节点之上,因此传递 IComparer 是不够的。当两个节点都有/没有子节点时,它们按字典顺序排序(OrdinalIgnoreCase)。

.net 中是否有可以满足我需求的数据结构?

此外,有没有办法在插入字典时为键提供散列,然后从字典中获取存储桶的一部分(即:GetValuesByHash(int hashValue) 产生其对应键具有给定散列的所有值) ? 我正在读取的文件表已经包含整个文件路径的哈希值(适用于我正在做的另一件事),目前,字典只是无缘无故地重新计算它们。

我想我可以通过定义我自己的自定义键来组合一个解决方案,其中包含 { Hash, Node } 以及自定义比较器,但这看起来真的很难看,而且你将无法获得共享相同哈希的节点桶。如果有的话,那仍然感觉像是使用了错误的数据结构。

我已经用谷歌搜索了“c# dictionary get hash”以及其他一些查询,但在这一点上,我还没有看到任何类似的问题。

总体而言,寻找具有以下属性的数据结构(可能与字典有关):

  • ContainsKeyOfHash(), Get(hash): 文件名哈希 -> 文件条目描述符
  • ContainsKey(), Get(key): 文件名 -> 文件条目描述符
  • Add(string fileName, Entry entry, int hash = gethash(fileName))
  • 条目排序如下:

        m_children.Sort(
           (a, b) => {
              bool aHasChildren = a.HasChildren;
              bool bHasChildren = b.HasChildren;
              if (aHasChildren && !bHasChildren)
                 return 1;
              if (!aHasChildren && bHasChildren)
                 return -1;
              else
                 return -String.Compare(a.m_resourceName, b.m_resourceName, StringComparison.OrdinalIgnoreCase);
           }
        );
    
  • 可以按上述排序顺序检索所有子节点。目前,我有一个 ChildrenSorted 和 ChildrenUnsorted 属性。ChildrenSorted 属性可能会因排序而导致性能下降,而 ChildrenUnsorted 属性则不会。

我认为更糟糕的是,我的解决方案是编写我自己的类字典类。我不必从字典中删除键,所以应该不难。不过,我有点想避免这样做。

我的节点实现可以查看: http: //pastie.org/5547925

谢谢!

4

2 回答 2

1

我认为您的解决方案已经很不错了。以下是一些想法:

  1. 对于一个既排序又可以按键快速访问的集合,我只能想到树数据结构。您可能不想要为每个项目分配一个对象的数据结构。可能所有项目都放在一个数组中的一种堆为您提供最好的服务。我认为您可以通过首先对所有孩子进行排序然后填充它们来非常有效地构建该结构(就像您现在正在做的那样)。
  2. 您可能会考虑将所有数据填充到一个这样的树中。这将为您节省大部分每个节点的开销(例如本身具有子对象的集合)。关键是节点的“路径”,以某种有效的格式存储。它可以是类似的路径,也可以"d1\d2\filename"string[].

第 (2) 点将是 RDBMS 将如何做到这一点。

于 2012-12-18T16:09:20.563 回答
0

您可以SortedDictionary通过简单地将您的Sort()lambda 放入 `IComparer:

public class MyComparer : IComparer, IComparer<MyNode>
{
    public int Compare(object x, object y)
    {
        return Compare(x as MyNode, y as MyNode);
    }

    public int Compare(MyNode x, MyNode y)
    {
        if (ReferenceEquals(x, y))
        {
            return 0;
        }

        if (ReferenceEquals(x, null))
        {
            return -1;
        }

        if (ReferenceEquals(y, null))
        {
            return 1;
        }

        bool xHasChildren = x.HasChildren;
        bool yHasChildren = y.HasChildren;
        if (xHasChildren && !yHasChildren)
            return 1;
        if (!xHasChildren && yHasChildren)
            return -1;
        else
            return String.Compare(y.m_resourceName, x.m_resourceName, StringComparison.OrdinalIgnoreCase);
    }
}
于 2012-12-18T16:08:59.477 回答