C++ 周围物体算法

C++ 周围物体算法,c++,C++,我正在制作一个游戏,其中只有一个对象可能存在于位置(x,y),其中x和y是int。例如,一个对象可能存在于(0,0)处,也可能不存在,但不可能同时存在多个对象 我正在尝试决定使用哪个STL容器来解决手头的问题,以及解决这个问题的最佳方法 基本上,我从一个对象及其(x,y)位置开始。目标是根据对象周围的对象确定最高的、可能最大的矩形。必须使用当前对象上方和下方的所有对象创建矩形。也就是说,它必须是基于起始对象位置可能达到的最高点 例如,假设以下内容表示我的对象网格,我从位置(3,4)处的绿色对象开

我正在制作一个游戏,其中只有一个对象可能存在于位置
(x,y)
,其中
x
y
int
。例如,一个对象可能存在于
(0,0)
处,也可能不存在,但不可能同时存在多个对象

我正在尝试决定使用哪个STL容器来解决手头的问题,以及解决这个问题的最佳方法

基本上,我从一个对象及其
(x,y)
位置开始。目标是根据对象周围的对象确定最高的、可能最大的矩形。必须使用当前对象上方和下方的所有对象创建矩形。也就是说,它必须是基于起始对象位置可能达到的最高点

例如,假设以下内容表示我的对象网格,我从位置
(3,4)
处的绿色对象开始:

然后,我要查找的矩形将由下面的粉色正方形表示:

因此,假设我从
(3,4)
处的对象开始,如示例所示,我需要检查
(2,4)
(4,4)
(3,3)
(3,5)
处是否也存在对象。如果一个对象存在于这些位置中的任何一个,我需要重复这个过程,让该对象找到可能的最大矩形

这些物品非常罕见,游戏世界非常庞大。对于整个游戏世界来说,仅仅
new
一个2D数组似乎并不实用,因为大多数元素都是空的。但是,我需要索引到任何位置,以检查对象在任何时候是否存在

相反,我考虑使用
std::map
如下:

std::map< std::pair<int, int>, ObjectData> m_objects;
如果我决定这样做,我可能会对
map::find()
进行大量调用,但与使用整个世界的二维数组相比,map占用的内存要少得多


有没有人对一个简单的算法有什么建议,我可以用它来找到我要找的东西?我是否应该继续使用
std::map
,或者是否有更好的容器来处理此类问题?

如果可能的话,改进方法是使用hashmap。这将允许您至少以O(1)的预期时间复杂度进行潜在的广泛搜索

这里有一个线程()详细介绍了如何将两个整数散列在一起


如果编译器支持C++11,则可以使用std::无序_映射。如果不是,Boost基本上是一样的:

你可能想考虑一个空间数据结构。如您所说,如果数据是“稀疏的”,那么进行四叉树邻域搜索可能会节省大量处理能力。我个人会使用R-tree,但这很可能是因为我有一个R-tree库,我已经编写好了,可以很容易地导入

例如,假设您有一个包含10000个元素的
1000x1000
网格。假设目前是均匀随机分布,我们(基于密度)预计不会超过,比如。一个由三到五个物体组成的链在任一维度上接触(在这个密度下,一个由三个垂直方向的物体组成的链发生的概率为0.01%)。假设所考虑的对象位于
(x,y)
。从
(x-5,y-5)
开始并转到
(x+5,y+5)
的窗口搜索将提供最多121个元素的列表,以执行线性搜索。如果您的矩形拾取算法注意到可能会形成一个更高的矩形(即,如果正在考虑的矩形接触此
11x11
边界框的边缘),只需在原始矩形的一个方向上重复窗口搜索另一个
5x5
区域。必要时重复

当然,这只有在数据非常稀疏的情况下才有效。可能需要调整R树,使叶子成为一个关联的数据结构(即
Int->Int->Object
),但在这一点上,可能最好只找到一个适用于更密集数据的解决方案

我可能想得太多了;可能有一个更简单的解决方案

关于R-树的一些参考:

  • ,对于原始算法
  • ,它对该主题有一些不错的概述
  • ,用于与R-树相关的数据集和算法

如果我有时间清理一下,我会用我自己的R-tree实现(公共域)的链接编辑它。

每个网格位置需要存储多少数据?如果你只是在寻找一个标志,表明你至少有两个“低技术”的解决方案

a) 如果你的网格是稀疏的,那么每个正方形都有一个邻居列表怎么样?所以每个方块都知道哪些相邻的方块被占据。当一个广场被占用或腾空时,您需要做一些工作来维护列表。但是邻居列表意味着你根本不需要网格地图


b) 如果栅格地图位置实际上只是点,则每个栅格位置使用1位。结果映射将比为每个网格点使用字节的映射小8x8=64倍。比特运算速度很快。10000x1000映射需要100000000位或12.5MB(约)

这听起来像是一个家庭作业问题(因为它有一个奇怪的条件“必须使用当前对象上下的所有对象创建矩形”,这使得解决方案变得微不足道)。不过我还是要试一试。为了方便起见,我将使用“像素”一词而不是“对象”

如果您的应用程序真的值得重量级解决方案,您可以尝试将像素存储在四叉树中(四叉树的叶子包含普通的二维数组,每个数组只有几千个像素)。或者,您可以将相邻像素组合成“形状”(例如,您的示例仅包含一个“形状”,即使它包含24个单独的像素)。给定初始非结构化
if(m_objects.find(std::pair<3, 4>) != m_objects.end())
{
    //An object exists at (3, 4).
    //Add it to the list of surrounding objects.
}
typedef std::pair<int, int> Pt;
typedef std::pair<Pt, Pt> Rectangle;
std::unordered_map<Pt, ObjectData *> myObjects;

/* This helper function checks a whole vertical stripe of pixels. */
static bool all_pixels_exist(int x, int min_y, int max_y)
{
    assert(min_y <= max_y);
    for (int y = min_y; y <= max_y; ++y) {
        if (myObjects.find(Pt(x, y)) == myObjects.end())
            return false;
    }
    return true;
}

Rectangle find_tallest_rectangle(int x, int y)
{
    assert(myObjects.find(Pt(x,y)) != myObjects.end());
    int top = y;
    int bottom = y;
    while (myObjects.find(Pt(x, top-1) != myObjects.end()) --top;
    while (myObjects.find(Pt(x, bottom+1) != myObjects.end()) ++bottom;
    // We've now identified the first vertical stripe of pixels.
    // The next step is to "paint-roller" that stripe to the left as far as possible...
    int left = x;
    while (all_pixels_exist(left-1, top, bottom)) --left;
    // ...and to the right.
    int right = x;
    while (all_pixels_exist(right+1, top, bottom)) ++right;
    return Rectangle(Pt(top, left), Pt(bottom, right));
}