SortedSet插入元素不正确

问题描述

我编写了A *的实现,该实现依赖于在sortedSet中按节点F分数对节点进行排序。

在某些情况下,排序似乎是在Node对象的“ F”值实际上是 second 最低值而不是Min值时插入“ Min”值,如上所述。我完全不知道为什么会这样。我相信这会引起连锁反应,导致nodeTree.Remove和nodeTree.RemoveWhere失败,但这可能是导致此问题的实际原因,我确实不确定-尽管我不知道如何解决此问题是的。

这是使用的比较器。我认为我不太清楚如何实现这些功能,这是相对明显的,但是我认为这应该可以按照我的预期进行。

    public class FValueFirst : Comparer<PathfindingAgent.Node>
    {
        public override int Compare(PathfindingAgent.Node x,PathfindingAgent.Node y)
        {
            int result = x.F.Compareto(y.F);

            if (result == 0)
            {
                result = y.G.Compareto(x.G);
            }
            
            if(x == y)
            {
                result = 0;
            }
            return result;
        }
    }

这是Node对象,仅供参考。

        public class Node
        {
            public Cell cell;
            public float G;
            public float H;
            public bool Opened;
            public bool Closed;
            public Node PrevIoUs;
            public float F { get => G + H; }
        }

这是全部发生的功能。谢天谢地,结果是确定性的。根据当前的destID和网格障碍物的特定布局,它会始终在同一迭代中变得混乱。

        public void PathTo(Vector3Int destID)
        {
            SortedSet<Node> nodeTree = new SortedSet<Node>(new FValueFirst());
            Vector3Int radius = PathfindingGrid.Instance.GridRadius;
            NodeGrid = new Node[radius.x * 2 + 1,radius.y * 2 + 1,radius.z * 2 + 1];
            Node startNode = new Node()
            {
                cell = PathfindingGrid.Cells[CurrentID.x,CurrentID.y,CurrentID.z],G = 0,H = 0
            };
            Node endNode = new Node()
            {
                cell = PathfindingGrid.Cells[destID.x,destID.y,destID.z],H = 0
            };
            Vector3Int sID = startNode.cell.ID;
            Vector3Int eID = endNode.cell.ID;
            NodeGrid[sID.x,sID.y,sID.z] = startNode;
            NodeGrid[eID.x,eID.y,eID.z] = endNode;

            if (endNode.cell.IsOccupied) return;

            nodeTree.Add(startNode);
            int iterations = 0;
            while(true)
            {
                Node node;
                node = nodeTree.Min;
                node.Closed = true;
                nodeTree.RemoveWhere(n => n == node);
                if(node == nodeTree.Min)
                {
                    throw new Exception($"Incorrect node was removed from the tree");
                }

                if (node == endNode)
                {
                    List<Node> chain = BacktraceChain(node);
                    Debug.Log($"Path found from {CurrentID} to {destID} with score {endNode.G} traversing {chain.Count} cells in {iterations} iterations");
                    DrawLine(chain,Color.white);
                    break;
                }
                List<Node> neighbours = GetNeighbours(node);
                foreach(Node neighbour in neighbours)
                {
                    if (neighbour == startNode || neighbour.Closed) continue;

                    float newg = Vector3Int.distance(node.cell.ID,neighbour.cell.ID) + node.G;

                    if (!neighbour.Opened || newg < neighbour.G)
                    {
                        neighbour.G = newg;
                        neighbour.H = ManhattanHeuristic(neighbour,endNode);
                        neighbour.PrevIoUs = node;

                        if(!neighbour.Opened)
                        {
                            nodeTree.Add(neighbour);
                            neighbour.Opened = true;
                        }
                        else
                        {
                            nodeTree.RemoveWhere(n => n == neighbour);
                            nodeTree.Add(neighbour);
                        }
                    }
                }
                iterations++;
            }
        }

解决方法

为了后代,我解决了这个问题-这是由于我对SortedList类型的经验不足。

在函数结尾处发现的这段代码应归咎于

style: {
  base: {
    backgroundColor: 'red',}
}

特别是,树中的项目无法将其比较值修改为不再在该索引中正确比较的程度。该项目必须 first 从列表中删除,修改和读取。

事后看来,我的猜测是,尽管在修改后立即将其删除,但由于修改,该树无法被充分遍历以访问目标项。

因此,我的解决方案是简单地重新排列块,以使删除和添加分别发生在修改的两侧,就像这样:

                    if (!neighbour.Opened || newg < neighbour.G)
                    {
                        neighbour.G = newg;
                        neighbour.H = ManhattanHeuristic(neighbour,endNode);
                        neighbour.Previous = node;

                        if(!neighbour.Opened)
                        {
                            nodeTree.Add(neighbour);
                            neighbour.Opened = true;
                        }
                        else
                        {
                            nodeTree.RemoveWhere(n => n == neighbour);
                            nodeTree.Add(neighbour);
                        }