【问题标题】:Need help for search optimization需要帮助进行搜索优化
【发布时间】:2013-12-26 17:31:09
【问题描述】:

我对编程相当陌生,我需要一些优化方面的帮助。 基本上我的方法的一部分是:

for(int i = 0; i < Tiles.Length; i++)
{
    x = Tiles[i].WorldPosition.x;
    y = Tiles[i].WorldPosition.y;
    z = Tiles[i].WorldPosition.z;

    Tile topsearch = Array.Find(Tiles,
        search => search.WorldPosition == Tiles[i].WorldPosition +
            new Vector3Int(0,1,0));

    if(topsearch.isEmpty)
    {
        // DoMyThing
    }
}

所以我在当前 Tile 上方 1 个单位的位置搜索 Tile。 我的问题是,对于整个方法,它需要 0.1 秒,这会导致一个小问题。如果没有 Array.Find,该方法是 0.01 秒。

我也尝试了一个 for 循环,但仍然不是很好的结果,因为我还需要 3 次检查 底部,左侧和右侧..

有人可以帮助我并指出一种快速获得结果的方法吗? 也许我应该使用线程之类的东西?

【问题讨论】:

  • 如果“查找”是一项您经常执行的操作并且它需要快速,则构建某种辅助存储——通常是字典——从搜索键映射到项目.字典针对快速搜索进行了优化。
  • @EricLippert,你知道我在想同样的事情,但后来又猜到了,因为你使用内存只是为了查找一个值。但是,既然您已经说明了;至少我走的是正确的思想流派。
  • @MichaelPerrenoud:您几乎总是可以用内存换取速度。这取决于哪种资源便宜。在移动设备上,以较低的速度换取较少的内存使用通常更明智;在台式机和服务器设备上,尤其是 64 位设备上,以更多的内存使用换取更高的速度通常是一种胜利。当然,您付出的代价不仅仅是更多的内存使用;它使数据结构更加复杂,可能会引入错误。而且您正在减慢每次插入的速度,以使每次查找速度更快。
  • @EricLippert,所以除非你在移动设备上,否则你会像证明数据库中的新索引一样证明它是合理的。查找速度可以提高几个数量级,但如果是高事务环境,则可能毫无价值。
  • @MichaelPerrenoud:正确;指数做出同样的权衡。由于必须维护索引属性,所有插入变得稍慢,并且由于索引数据必须存储在某处,数据库大小增加,但查找变为 O(lg n) 或 O(1) 而不是 O(n)。跨度>

标签: c# optimization


【解决方案1】:

您可以创建一个 3 维数组,这样您就可以通过查看 Tiles[x, y + 1, z] 中的内容来查找特定位置的图块。

然后您可以在 2 个循环中遍历您的数据:一个用于构建 Tiles,另一个用于执行您在上面的代码中所做的检查,然后就是:

for(int i = 0; i < Tiles.Length; i++)
{
    Tile toFind = Tiles[Tile[i].x, Tile[i].y + 1, Tile[i].z];
    if (toFind != null) ...
}

您必须对数组进行标注,以便在 y 中有 1 行额外的行,这样Tiles[x, y + 1, z] 就不会导致索引超出范围异常。

【讨论】:

  • 要走的路,除非x、y和z是天文数字而且网格很稀疏。
  • @Rotem,在这种情况下,您可以使用稀疏网格习语。
  • 我想我会去尝试一下。谢谢。
【解决方案2】:

添加到Roy's solution,如果空间可能不连续,您可以在这里使用WorldPosition(x、y 和z 坐标)的哈希码。

我的意思是你可以用你自己的实现覆盖WorldPositionGetHashCode

public class WorldPosition
{
    public int X;
    public int Y;
    public int Z;

    public override int GetHashCode()
    {
        int result = X.GetHashCode();
        result = (result * 397) ^ Y.GetHashCode();
        result = (result * 397) ^ Z.GetHashCode();
        return result;
    }
}

请参阅Why is '397' used for ReSharper GetHashCode override? 了解说明。

然后您可以将您的图块放入Dictionary&lt;WorldPosition, Tile&gt;

这将允许快速查找dict[new WorldPosition(x, y, z + 1)] 等。字典使用哈希码作为键,所以它会很快。

【讨论】:

  • 397 的东西很吸引人。
  • 这不是我通过 ReSharper 学到的唯一东西 :) 顺便说一句,请注意对于非常大的世界存在哈希冲突的风险,因此也应该考虑到这一点。跨度>
  • ...2^32 小于 1625^3 - 换句话说,如果世界是 1625 x 1625 x 1625,则没有足够的 32 位整数来提供唯一的哈希值和概率哈希冲突达到 100%。但是,使用 64 位哈希看起来要好得多。
【解决方案3】:

首先,像@Roy 建议的那样,尝试将值存储在一个数组中,以便您可以使用 x、y、z 坐标访问它们,

您可以做的另一件事是将搜索更改为

Tile topsearch = Array.Find(Tiles,
        search => search.WorldPosition.x == Tiles[i].WorldPosition.x && 
        search.WorldPosition.y == (Tiles[i].WorldPosition.y + 1) &&
        search.WorldPosition.z == Tiles[i].WorldPosition.z)

这也可能更快,具体取决于您的 WorldPosition 有多少字段

【讨论】:

    猜你喜欢
    • 2010-10-31
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    • 2023-01-27
    • 1970-01-01
    • 1970-01-01
    • 2020-08-03
    • 2014-05-20
    相关资源
    最近更新 更多