You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻找2D网格中指定Tile所有8方向邻居的高效查找算法

高效获取锯齿数组中Tile的8方向邻居实现方案

问题背景

你在C#开发中使用自定义Tile对象的锯齿数组,需要实现GetNeighbors方法返回指定索引Tile的8方向邻居队列,且已知输入索引合法。当前实现通过多层分支判断来减少检查次数,但平均仍需5-6次条件检查,希望获得更高效的实现。

原方法定义

private Tile[][] tileGrid;
private Queue<Tile> GetNeighbors(int r, int c) { ...}

原实现代码

Queue<Tile> neighbors = new Queue<Tile>(8);
if (r != 0 && r != tileGrid.Length) //If not on first or last row
{
    neighbors.Enqueue(tileGrid[r+1][c]); 
    neighbors.Enqueue(tileGrid[r-1][c]);
    if (c != tileGrid[r].Length) //If not on last column
    {
        neighbors.Enqueue(tileGrid[r+1][c+1]); 
        neighbors.Enqueue(tileGrid[r][c+1]);
        neighbors.Enqueue(tileGrid[r-1][c+1]);
    }
    if (c != 0) //If not on first column
    {
        neighbors.Enqueue(tileGrid[r-1][c-1]); 
        neighbors.Enqueue(tileGrid[r][c - 1]);
        neighbors.Enqueue(tileGrid[r+1][c-1]);
    }
}
else if (c != 0 && c != tileGrid[r].Length) //Confirms if the tile is on 1st or last row but isn't a corner tile
{
    neighbors.Enqueue(tileGrid[r][c-1]); neighbors.Enqueue(tileGrid[r][c+1]);
    if (r == 0) //if on first row but not corner
    {
        neighbors.Enqueue(tileGrid[r+1][c]); 
        neighbors.Enqueue(tileGrid[r+1][c+1]);
        neighbors.Enqueue(tileGrid[r+1][c-1]);
    }
    else //For last row but not corner
    {
        neighbors.Enqueue(tileGrid[r-1][c]); 
        neighbors.Enqueue(tileGrid[r-1][c+1]);
        neighbors.Enqueue(tileGrid[r-1][c-1]);
    }
}
else
{
    if(r == 0) //if upper corner
    {
        neighbors.Enqueue(tileGrid[r+1][c+1]);
        if(c == 0) 
        { 
           neighbors.Enqueue(tileGrid[r+1][c+1]); 
           neighbors.Enqueue(tileGrid[r][c+1]); 
        }
        else 
        { 
          neighbors.Enqueue(tileGrid[r+1][c-1]); 
          neighbors.Enqueue(tileGrid[r][c-1]); 
        }
    } else //if lower corner
    {
        neighbors.Enqueue(tileGrid[r-1][c]);
        if(c==0) 
        { 
           neighbors.Enqueue(tileGrid[r-1][c+1]); 
           neighbors.Enqueue(tileGrid[r][c+1]); 
        }
        else 
        { 
           neighbors.Enqueue(tileGrid[r-1][c-1]); 
           neighbors.Enqueue(tileGrid[r][c-1]); 
        }
    }
}
return neighbors;

优化方案:预定义方向偏移量+线性遍历

核心思路

放弃复杂的分支判断,转而预定义8个方向的行列偏移量数组,遍历每个偏移量计算邻居索引,仅在索引合法时将对应Tile加入队列。这种方式的优势在于:

  • 逻辑统一,代码简洁易维护;
  • 避免复杂分支带来的CPU分支预测失败开销;
  • 简单的范围判断能被编译器充分优化,实际执行效率更稳定。

通用伪代码

// 预定义8个方向的行列偏移量(顺序可按需调整)
directionOffsets = [(-1,0), (1,0), (0,-1), (0,1), (-1,-1), (-1,1), (1,-1), (1,1)]

function GetNeighbors(r, c):
    neighbors = new Queue(8)
    totalRows = length(tileGrid)
    for each (dr, dc) in directionOffsets:
        neighborRow = r + dr
        neighborCol = c + dc
        // 检查行索引合法,且列索引在当前行的有效范围内
        if neighborRow >= 0 and neighborRow < totalRows and neighborCol >= 0 and neighborCol < length(tileGrid[neighborRow]):
            neighbors.enqueue(tileGrid[neighborRow][neighborCol])
    return neighbors

C# 实现代码

// 将偏移量定义为类的静态常量,避免每次方法调用重复创建数组
private static readonly (int dr, int dc)[] _directionOffsets = 
{
    (-1, 0), (1, 0), (0, -1), (0, 1),
    (-1, -1), (-1, 1), (1, -1), (1, 1)
};

private Queue<Tile> GetNeighbors(int r, int c)
{
    var neighbors = new Queue<Tile>(8);
    int totalRows = tileGrid.Length;
    
    foreach (var (dr, dc) in _directionOffsets)
    {
        int nr = r + dr;
        int nc = c + dc;
        
        // 验证邻居索引的合法性:行在范围内,且列在该行的有效范围内
        if (nr >= 0 && nr < totalRows && nc >= 0 && nc < tileGrid[nr].Length)
        {
            neighbors.Enqueue(tileGrid[nr][nc]);
        }
    }
    
    return neighbors;
}

效率说明

  • 原实现的多层分支看似减少了检查次数,但复杂的分支结构容易触发CPU分支预测失败,反而增加执行开销;
  • 优化后的实现采用线性遍历,每个循环的条件检查都是简单的数值比较,CPU能高效流水线执行,实际性能更优;
  • 由于输入索引合法,大部分偏移量都会通过检查,遍历的额外开销可以忽略。

内容的提问来源于stack exchange,提问作者Neptunium-Eater

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 16:57:26