从2D节点阵列优化邻接矩阵创建

时间:2015-02-24 23:27:35

标签: c# unity3d cluster-analysis adjacency-matrix

我试图从2D节点阵列创建一个邻接矩阵。邻接矩阵将传递给一个程序,该程序将通过

聚类节点
  1. 光谱聚类算法
  2. Kmeans聚类算法
  3. **节点类**

        public class Node{
        public int _id;
        public bool _isWalkable;
        public int _positionX;
        public int _positionY;
        public Vector3 _worldPosition;
        }
    

    网格类

        public class Grid : MonoBehaviour
        {
    
            void CreateGrid()
            {
            grid = new Node[_gridSizeX, _gridSizeY];
            Vector3 worldBottomLeft =  transform.position - 
            Vector3.right * worldSize.x / 2 - Vector3.forward * worldSize.y / 2;
    
            //set the grid
            int id = 0;
    
            for (int x = 0; x < _gridSizeX; x++)
            {
                for (int y = 0; y < _gridSizeY; y++)
                {
                    Vector3 worldPosition = worldBottomLeft + Vector3.right * 
                        (x * _nodeDiameter + _nodeRadius) + 
                        Vector3.forward * (y * _nodeDiameter + _nodeRadius);
                    //check to see if current position is walkable
                    bool isWalkable = 
                        !Physics.CheckSphere(worldPosition, _nodeRadius, UnwalkableMask);
    
                    grid[x, y] = new Node(isWalkable, worldPosition, x, y);
                    grid[x, y].Id = id ++;
    
                }
            }
            totalNodes = id;
        }
    }
    

    节点存储在名为grid的2D数组中,表示要移动的角色的可行走路径。我已成功实现了具有欧氏距离启发式的A *算法。我想要做的是使用上述聚类算法聚类这些节点,但首先我需要为它们创建一个邻接算法。这是我能提出的最好的伪代码

        int[][] _adjacencyMatrix = new int[gridSizeX*gridSizeY][gridSizeX*gridSizeY];
    
        for(int x = 0; x < gridSize;x< XgridSize; i++)
        {
             for(int y = 0; y < gridSize;y< YgridSize; i++)
             {
               if( !Grid[x][y]._isWalkable)
                  continue;
               Node n = Grid[x][y];
               List<Node> neighbors = GetNeighbors(n);
               for(int k; k<neighbors.Count(); k++)
                {
                    _adjacencyMatrix[n._id][neighbors[k]._id]=1; 
                }
             }
        }
    
        public List<Node> GetNeighbours(Node n)
        {
            //where is this node in the grid?
            List<Node> neighbours = new List<Node>();
    
            //this will search in a 3X3 block
            for (int x = -1; x <= 1; x++)
            {
                for (int y = -1; y <= 1; y++)
                {
                    if (x == 0 && y == 0)
                        continue; //we're at the current node
    
                    int checkX = n._positionX + x;
                    int checkY = n._positionY + y;
    
                    if (checkX >= 0 && checkX < _gridSizeX && checkY >= 0 
                        && checkY < _gridSizeY)
                    {
                        if(grid[checkX, checkY]._isWalkable)
                            neighbours.Add(grid[checkX, checkY]);
                        else
                            continue;
                    }
                }
    
            }
            return neighbours;
    
        }
    

    我的主要关注点

    我主要担心的是上述算法的总体复杂性。感觉它会变得沉重,我在邻接矩阵中总共有(75 ^ 2 = 5625)个节点,大小为5625X5625!找到邻居必须有比这更好的方法吗?

2 个答案:

答案 0 :(得分:1)

矩阵是对称的,所以你只需要保存一半,参见(How to store a symmetric matrix?)作为例子。矩阵值是二进制的,因此将它们保存为布尔值或位向量将分别将内存减少4或32倍。

或者,由于对两个相邻节点的检查需要恒定时间(abs(n1.x - n2.x) <= 1 && abs(n1.y - n1.y) <= 1 && grid[n1.x, n2.x].isWalkable() && grid[n2.x, n2.y]),因此您可以将聚类算法传递给动态检查邻接的函数。

答案 1 :(得分:0)

5k乘5k并不是很大。 100 MB是你可以留在内存中的东西。如果您想避免这种成本,请不要使用基于距离矩阵的算法!

但是,因为你的相似性似乎是

d(x,y)= 1如果相邻且两个节点都可以步行,那么0

你的结果会退化。如果你很幸运,你会得到类似连接组件的东西(你可以更容易)。 成对最短路径将更有用,但构建起来也更昂贵。不过可能考虑先解决这个问题。我认为拥有完整的邻接矩阵是一个很好的起点。

k-means根本无法与成对距离一起使用。对于任意方式,它只需要点到均值的距离。

在尝试将数据压缩到可能解决不同问题的聚类算法之前,我建议先查看图算法,然后花更多时间了解您的目标。