针对特定类型的查询的更好的数据结构

时间:2011-06-20 17:44:27

标签: c# data-structures

解决了这个问题,但是这个问题最近得到了一些关注,所以我正在添加我的解决方案(以及一些澄清)。见下文。


我有一个32位整数的列表,我想找到((item ^ bits) & mask) == 0为真的它们的子集。问题是,bitsmask都可以取任何值(mask偏向于设置的位数不是很多),所以我不能简单地预先计算所有可能的组合。

列表不是很大,通常大约有500个项目,所以理论上看起来很好的东西(例如二叉树,掩码中的每个位都可以跳过整个子树)在实践中实际上很慢。尽管跳过了大量的测试,即使只有两个级别的树也比天真的方法慢一点。

目前,我遍历整个列表并测试每个项目。它快一次,但它发生了数百万次,每次都有不同的bitsmask,因此缓存结果无济于事。程序的这一部分占用的CPU时间的40%以上。

foreach (var row in validRows.Keys)
{
    // this single line here takes 40% of the total program time, according to ANTS 5
    if (((oldrow ^ row) & oldused) == 0)
    // the other magic takes no significant time, according to ANTS
    {
        if (y > 1 && ((((row ^ prev) | yminone) + 1) >> rows.Length) == 0)
        {
            continue;
        }
        if (dict.ContainsKey(row))
            continue;

        dict.Add(row, true);

        rows[y] = row;
        count(y + 1, dict);   // this is a recursive call.

        dict.Remove(row);
    }
}

我收集了一些统计数据。事实证明,179000个查询中有超过130000个只返回1个项目。这听起来像是对我进行某种优化的机会,但我不确定如何或者是什么。


对于这个特殊的子问题,预处理有很大帮助。我现在为输入中的每一行创建一系列可能性,这只是validRows(现在是数组而不是字典),由(int row) => ((inputrow ^ row) & inputfilledmask) == 0过滤。

给定一个部分填充的8x8布尔矩阵,实际问题是计算满足以下规则的所有赋值:

  1. 每行4个和4个零
  2. 每列中有4个和4个零
  3. 垂直或水平相邻的不超过2个
  4. 垂直或水平彼此相邻的零不超过2个零
  5. 两行不等于
  6. 没有两列可能相等
  7. 以下是我现在解决的问题:

    对于每一行,将34个有效行的列表过滤到可以在其上分配的行(即,与掩码中的标记填充单元格的行相对应的所有位在输入行中相等以及可以在其上分配的行。)

    然后以递归方式填写下一行,该行包含每一个可能的行。这意味着它必须位于已过滤的列表中,它必须尚未使用(即不在哈希集中),并且进行测试以确保它不违反第4条规则。为了修剪递归树的一些子树,我还使用了两个额外的整数,一个用于跟踪每列中的零个数(每列一个半字节),另一个用于跟踪那些。简明测试会忽略违反第二条规则的潜在行。这些整数初始化对应于输入(加0x33333333,因此列中的4个不设置半字节的最高位但是5个或更多),并且仅使用先前为空的单元格进行更新。

    最后,在递归树的底部,最后一行完全由两个整数决定,这两个整数计算列中的1和0(即使其中只有一个足以确定最后一行)。然后对重复的列进行测试 - 这是唯一不能通过构造自动保证的。总之,时间从大约一分钟下降到大约十分之一秒(通常更少)。

    我仍然愿意接受建议(尽管这会使这个问题成为一个完全不同的问题)。此计数例程用于通过强力生成“良好”的初始配置 - 运行得越快,在指定时间内的结果就越好。

2 个答案:

答案 0 :(得分:1)

我认为您正专注于解决方案的错误部分。虽然这个循环中有很多CPU时间,但它本身无法进行很多优化。

我使用预先计算的列表进行了测试,其中包含为特定位设置或清除位的整数,并根据位和掩码中的值组合列表。尽管速度非常快,但仍然需要花费十倍的时间来计算数值。

你必须在循环之外看看数据实际意味着什么,以找到消除某些工作的方法。

答案 1 :(得分:0)

您要求更好的数据结构,但如果没有,那该怎么办?

你可以考虑退一步看看你的问题,看看你是否可以使用多个线程或并行结构,这样你就可以一次使用多个处理器。