通过散列来改进集合比较(过于聪明......?)

时间:2010-03-06 20:16:45

标签: c# optimization hash

在我上次失败之后,尝试在这里提出一个问题,这次我正在尝试一个更精确的问题:

我有什么:

  1. ISet<Point>的一个庞大的数据集(有限,但我浪费了几天的多核处理时间来计算它......)。
  2. 0到2之间的输入值列表 n ,n≤17
  3. 我需要什么:

    3)[1],[2]的表格,其中我将[2]的每个值映射到值[1]

    处理:

    对于这个计算,我有一个公式,它取一个位值(来自[2])和一组位置(来自[1])并创建一个新的ISet<Point>。我需要找出哪个原始集合等于结果集合(即“A7”表中的“单元格”可能指向“B”)。

    天真的方式:

    计算新的ISet<Point>并在[1]的值列表中使用.Contains(mySet)或类似内容。我在此概念验证/宠物项目的先前版本中做到了这一点,当我开始提供大量数据时,它已经死了。是的,我使用了一个分析器。不,这不是系统中唯一缓慢的部分,但是我在这个天真的查找/映射中浪费了相当多的时间。

    问题,最后:

    由于我基本上只需要重新映射到输入,我考虑为ISet<Point>列表创建一个散列值列表,对我处理的结果做同样的事情,因此避免比较整个集合。

    这是个好主意吗?你会称之为过早的优化(我知道上面的天真的方式太慢了,但我应该先实现一些不那么聪明的东西吗?性能在这里非常重要,再想想运行时间)?任何其他建议,以缓解这里的burdon或想法我应该阅读?


    更新:很抱歉没有提供更好的解释或样品。

    [1]的样本(注意:这些是真正可能的数据点,但显然它是有限的):

    new List<ISet<Point>>() {
      new HashSet() {new Point(0,0) },
      new HashSet() {new Point(0,0), new Point(2,1) },
      new HashSet() {new Point(0,1), new Point(3,1) }
    }
    

    [2]只是长度为n的布尔矢量。对于n = 2,它是

    • 0,0
    • 0,1
    • 1,0
    • 1,1

    我可以通过使用int或long来完成那个,基本上。

    现在我有一个带矢量和ISet<Point>的函数,并返回一个新的ISet<Point>。这不是1:1的转换:一组5可能会导致一组11或其他。结果ISet<Point> 但保证是输入的一部分。

    使用字母表示位向量的一组点和数字,我从这个

    开始
      A  B  C  D  E  F
    1
    2
    3
    4
    5
    6
    7
    

    最后我需要的是

      A  B  C  D  E  F
    1 -  C  A  E  -  -
    2 B  C  E  F  A  -
    3 ................
    4 ................
    5 ................
    6 F  C  B  A  -  - 
    7 E  -  C  A  -  D
    

    这些项目中有几个代价高昂的操作,一个是点集([1])的编写。但是这个问题是关于现在的匹配:我可以轻松地(或多或少,现在不那么重要)计算给定位向量和源ISet的目标ISet。现在我需要在原始集中匹配/找到它。

    整个野兽将成为状态机,其中点集是有效状态。后来我不关心各个州,我实际上可以通过任何东西(一封信,一个索引,等等)来引用它们。我只需要保持联想:

    1,B =&gt; ç


    更新:Eric询问是否可以使用HashSet。答案是肯定的,但前提是数据集足够小。我的问题(哈希)是:对于这个哈希集,可能采用哈希算法是否可能/一个好主意?我的想法是:

    • 走{懒惰生成的} ISet<Point>列表/序列(我可以改变这种类型,我只想强调它是一组数学点,没有重复)。

      • 创建一个更简单的输入表示(一个哈希?)并存储它(在一个哈希集中?)
      • 计算此输入的所有目标集,但仅再次存储简单表示(参见上文)
      • 弃掉套装
    • 修复映射(相等哈希=相等状态)

    好主意?有这个问题?我能想出的一个是碰撞(这有多可能?) - 我不会知道一个好的哈希函数开始......

1 个答案:

答案 0 :(得分:3)

好吧,我想至少我现在理解这个问题了。让我看看我是否可以改写。

让我们先把它们留下来。我们会保持抽象。

您有一个大型列表L,包含引用类型为S的实例(用于“set”)。这样的列表当然在逻辑上是从自然数N到S的映射。

L: N --> S

S具有可以比较引用相等和值相等的两个实例的属性。也就是说,可能有两个S的实例,它们不是引用等号,但在逻辑上代表相同的值。

你有一个函数F,它取一个V型值(对于“vector”)和一个S型实例,并产生另一个S型实例。

F: (V, S) --> S

此外,你知道如果F从L给出一个S实例,那么结果S的实例将值等于到列表中的某个东西,但不一定引用等于< / em>的

你面临的问题是:给定一个S的实例s,这是对F的调用的结果,哪个成员L(n)的值等于s?

天真的方法 - 沿着L(1),L(2),......沿途的测试集平等将是死慢的。 L的大小至少是线性的。

我可以想到几种不同的方法。最简单的是你最初的想法:使L不是列表。你能把它变成HashSet<S>而不是List<S>吗?如果在S上实现散列算法和相等方法,则可以构建快速查找表。

如果不合适,我们将探索其他选择。

更新:

好的,所以我可以看到两种基本的方法来处理你的记忆问题。 (1)使用比当前实现小得多的数据结构将所有内容保存在内存中,或者(2)更改在磁盘上存储内容的方式,以便在内存中存储“索引”并快速转到右侧“页面”磁盘文件,以提取您需要的信息。

您可以将一个点表示为单个short,其中顶部字节为x,底部字节为y,而不是将其表示为两个整数;节省75%。

一组点可以实现为一个排序的short数组,它非常紧凑,很容易编写哈希算法。

这可能是我要采用的方法,因为您的数据是如此可压缩的。