【问题标题】:Recursively created linked lists with a class, C++使用类 C++ 递归创建的链表
【发布时间】:2010-05-25 01:04:20
【问题描述】:

我正在使用 C++ 递归地制作六边形网格(使用多重链表样式)。我已经将其设置为可以轻松创建相邻的图块,但是因为我是递归地执行此操作,所以我只能为给定的图块真正创建所有 6 个邻居。显然,这会导致创建重复的瓷砖,我正试图以某种方式摆脱它们。因为我正在使用一个类,所以检查空指针似乎不起作用。它要么无法从我的 Tile 类转换为 int,要么以某种方式转换它但没有正确执行。我在创建时明确将所有指针设置为 NULL,当我检查它是否仍然存在时,它说它不是即使我自初始化以来从未接触过它。有没有我应该这样做的特定方式?如果没有某种 NULL,我什至无法遍历网格

这是我的一些相关代码。是的,我知道这很尴尬。

平铺类头:

class Tile
{
public:
    Tile(void);
    Tile(char *Filename);
    ~Tile(void);

    void show(void);
    bool LoadGLTextures();
    void makeDisplayList();
    void BindTexture();
    void setFilename(char *newName);

    char Filename[100];
    GLuint texture[2];
    GLuint displayList;
    Tile *neighbor[6];
    float xPos, yPos,zPos;
};`

瓷砖初始化:

Tile::Tile(void)
{
    xPos=0.0f;
    yPos=0.0f;
    zPos=0.0f;
    glEnable(GL_DEPTH_TEST);
    strcpy(Filename, strcpy(Filename, "Data/BlueTile.bmp"));
    if(!BuildTexture(Filename, texture[0]))
        MessageBox(NULL,"Texture failed to load!","Crap!",MB_OK|MB_ICONASTERISK);

    for(int x=0;x<6;x++)
    {
        neighbor[x]=NULL;
    }
}

相邻图块的创建:

void MakeNeighbors(Tile *InputTile, int stacks)
{
    for(int x=0;x<6;x++)
    {
        InputTile->neighbor[x]=new Tile();
        InputTile->neighbor[x]->xPos=0.0f;
        InputTile->neighbor[x]->yPos=0.0f;
        InputTile->zPos=float(stacks);
    }
    if(stacks)
    {
        for(int x=0;x<6;x++)
            MakeNeighbors(InputTile->neighbor[x],stacks-1);
    }
}

最后,遍历网格:

void TraverseGrid(Tile *inputTile)
{
    Tile *temp;
    for(int x=0;x<6;x++)
        if(inputTile->neighbor[x])
        {
            temp=inputTile->neighbor[x];
            temp->xPos=0.0f;
            TraverseGrid(temp);
            //MessageBox(NULL,"Not Null!","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
        }

}

关键行是“if(inputTile->neighbor[x])”,无论我是“if(inputTile->neighbor[x]==NULL)”还是我做的任何事情,它都不能处理它正确。哦,我也知道我还没有完全设置列表。现在只有一个方向。

【问题讨论】:

  • 您还可以指定“未正确处理”的含义。
  • 这并不是一个真正适合递归的候选者。如果无法通过某种形式的坐标定位您的邻居,您就没有合理的方法将它们拼接在一起(显然是您遇到的问题)。您可以在创建它们之后将它们缝合在一起(newWestCell.northEastCell = this.northWestCell),但这很快就会变成一个非常麻烦的问题——并且仍然不是递归友好的。

标签: c++ linked-list hexagonal-tiles


【解决方案1】:

如果你想创建一个六边形网格,你应该记住,它可以很容易地使用普通网格来模拟!

    __    __    __
\__/2 \__/4 \__/6 \
/1 \__/3 \__/5 \__/
\__/8 \__/10\__/12\
/7 \__/9 \__/11\__/
\__/  \__/  \__/  \

这将使生活变得更加简单:)

因此最简单的方法是

  1. 设置临时方格m*n
  2. 用瓷砖填充它
  3. 穿越网格并正确连接

现在连接,根据上图:

A) Connect to previous and next [x-1,y], [x+1,y]
B) Connect to row above and row below [x,y-1], [x,y+1]
C) Connect to row above previous and next [x-1,y-1], [x+1,y-1]

...并且您拥有所有所需的连接(只需记住检查边界以确定图块是否不在边缘)-如果您以另一种方式握住图块,您甚至可以删除网格:)。

【讨论】:

  • 可以,但该图对我没有帮助。对于每个节点 (x,y) 与 (x-1,y),(x+1,y),(x,y-1),(x,y+1) 相邻的二维数组,蜂窝模式类似于在偶数行上附加链接到 (x+1,y-1),(x+1,y+1) 和奇数行上附加链接到 (x-1,y-1),(x-1,y+1)行。
  • 诀窍是,首先将六边形挤压成交错的砖块,然后看看砖块与规则网格的关系。
  • @Potatoswatter,这里,ph34r 我的 l33t ascii Skillz ;>
  • 我已经找到了一种使用坐标系的方法,并且我拥有创建合适邻居的所有代码。 “处理不当”是指当我将指针设置为 NULL 时,然后检查它们是否为 NULL;我要么收到错误“无法从 Tile 转换为 int”,要么只是说它不是 NULL,即使我没有更改它。我注意到我知道它们尚未正确链接。我只是还没有实现它。我想要这样做的方式还需要能够检查 NULL 指针,所以这是第一位的。感谢您的回复
  • 这实际上是一个相当困难的解决方案。您必须知道您在偶数行或奇数行的天气才能确定“NE”。例如,9 的 NE 是 10,但 10 的 NE 是 5。这到底是怎么回事?但是为那些令人敬畏的图形 +8 是非常值得的。
【解决方案2】:

我只是猜测 MakeNeighbors() 做了什么,但与其盲目地做InputTile-&gt;neighbor[x]=new Tile();,不如在创建新邻居并初始化它之前检查邻居[x] 是否为非 NULL。例如。如果它的父级创建了它并设置了它的所有邻居信息,那么它不应该去创建它的父级。

当父母创建孩子时,它还应该适当地定义孩子的其他邻居,只要它知道他们。因此,它应该确保 child[i] 也是 child[i-1] 和 child[i+1] 的邻居。

【讨论】:

    【解决方案3】:

    创造。递归是解决某些问题的一种简洁优雅的方法,但它并不适合所有问题。我怀疑创建节点的纯递归解决方案会比Kornel Kisielewicz's straightforward iterative solution 复杂得多(即less 优雅)。这是因为Tile 构造函数需要知道其附近所有图块的布局,以避免重新创建已经存在的节点。

    遍历。 节点遍历代码中的主要问题是相似的,因为每个节点最终都会“遍历”回其父节点,因此您将陷入无限循环并破坏堆栈,再次开始循环。我想您正试图只访问每个图块一次,对吗?在那种情况下,TraverseGrid() 需要有一个参数告诉它我们从哪个方向进入节点,这样我们就可以避免从那个方向返回。

    但这还不够——您还需要更加自律地决定去往哪个方向。简单地向所有方向展开,除了我们输入的方向之外,仍然会陷入无限循环和堆栈溢出,因为任何三个相邻的图块都会无限循环。为了递归地执行此操作,您需要真正考虑哪些策略最终会访问每个节点一次且仅一次。

    一种可能性是将TraverseGrid() 的签名更改为TraverseGrid(Tile *inputTile, int fromDir, bool leftmost),然后使用以下规则:

    • 如果我们从左上角进入,只遍历右上角,通过leftmost = false
    • 如果我们从左下或右上进入,只遍历到右下,通过leftmost = false
    • 如果leftmost,并且我们的左下角有一个节点,那么也遍历到那个节点,传递leftmost = true

    当然fromDirleftmost 可以组合成一个参数,但这给出了大致的思路。

    另一种选择是在每个图块中保留一个visited 标志,在遍历该图块之前对其进行检查。那么您的遍历将是flood fill。但同样,简单的迭代遍历可能更加更简单、更容易理解,并且具有使用恒定堆栈空间的额外好处。

    【讨论】:

      【解决方案4】:

      在类声明中有第二个构造函数Tile(char *Filename);。也许这个构造函数用于创建主节点,但没有正确初始化neighbor? (未显示其实现。)

      在不相关的节点上,构造函数中有一个重复的strcpy(),它没有任何用途,可能只会导致问题:

      strcpy(Filename, strcpy(Filename, "Data/BlueTile.bmp"));
      

      【讨论】:

      • 哦,哈哈,是的。我以前用它做一些不同的事情。感谢您指出这一点。
      • 我使用其他构造函数来指定非默认纹理
      【解决方案5】:

      我实际上做了同样的事情,但我的模式更像这样:

      00   01   02   03   04
      
         10    11   12   13   14
      
            20    21   22   23   24
      
               30   31   32   33   34
      

      这使得很容易弄清楚可以达到什么,但会产生一种奇怪的偏移模式。我刚刚摆脱了(在上面的例子中)00,01,10 和 20,使它更像是这样的十六进制模式:

                  02   03   04   05   06
      
               11   12   13   14   15
      
                  21   22   23   24   25
      
               30   31   32   33   34
      

      所以如果你看上面的模式,reachable 总是一样的:

      从 23(调用 2“a”和 3“b”)您可以到达:

      NW(a-1, b), NE(a-1, b+1), W(a, b-1), E(a, b+1), SW(a+1, b-1), SE(a+1,b)
      

      这种模式应该适用于整个网格。

      编辑:

      我打算在评论中这样做,但它太长了。我可以看到两种方法。

      1) 分配节点数组(null,不分配)。每当您需要分配一个节点时,就这样做,但是当您需要引用一个节点时使用数组地址,如果它为空,则填充它,如果它有一个值,则使用该值。巨大的空数组不应该占用那么多内存,但如果他们这样做......

      2) 创建一个 HashSet 来保存您的节点,其中节点类的哈希值计算如下:(a

      在已知边界的人口最多的系统中,1 将节省内存,但如果您的系统是稀疏的(如您声称的那样),那么 #2 可以节省大量内存而不会降低效率。

      【讨论】:

      • 是的,我已经掌握了所有这些。我正在研究的特定问题是一个代理使用一组特定的规则在一个块之间移动(我实际上是在用这个来模拟“兰顿的蚂蚁”。由于它的行为,它会很快达到边缘. 与其创建一个 MASSIVE 数组让它进入,我希望能够仅在必要时创建新的图块。
      • 其实看你的设置方式,比我设置的直观一点
      • 如果不希望分配整个数据结构,也许您应该考虑将其建模为隐式图——仅在需要时才发现/分配节点(瓦片)和边(连接点)的图。 Boost Graph Library 是一个非常健壮(尽管很复杂)的框架,可以在您走这条路时为您提供指导。然后,您可以在隐式图之上执行遍历和其他寻路算法。
      • @Jon Brant 此评论只是为了告诉您查看我的编辑以回应您的上述评论。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-12
      • 1970-01-01
      相关资源
      最近更新 更多