我有一个包含在SortedDictionary中的节点类:
SortedDictionary<Node, bool> openList = new SortedDictionary<Node, bool>();
我需要在节点上编写CompareTo方法,以便根据int值(F)从最低到最高对节点进行排序。我还需要能够根据字符的位置检查字典中是否已存在节点(此位置是节点唯一的原因)。 CompareTo看起来像这样:
public int CompareTo(Node other)
{
if (GridPosition != other.GridPosition)
{
if (F > other.F)
{
return 1;
}
if (F < other.F)
{
return -1;
}
return -1;
}
return 0;
}
问题是,它并不总是返回正确的结果。例如,即使节点在字典中,以下代码行也将返回false。但是它会按照我的意愿对我添加到字典中的所有节点进行排序。
Node node = new Node(); //It has a grid position and a f value
openList.add(node, false);
if(openList.Keys.Contains(node)) //this returns false
{
}
为了解决这个问题,我创建了一个EqualityComparer并在比较值时使用它。等式比较器如下所示:
class NodeEqualityComparer : IEqualityComparer<Node>
{
public bool Equals(Node x, Node y)
{
return x.GridPosition == y.GridPosition;
}
public int GetHashCode(Node obj)
{
return obj.GridPosition.GetHashCode();
}
}
我在SortedDictionary的Contains方法中使用此相等比较器作为参数,这样可以正常工作,并根据词典中的内容返回正确的结果:
if (openList.Keys.Contains(currentNode,new NodeEqualityComparer())) //This will return true if the node is in the dictionary
{
}
当我需要从Dictionary中删除节点时,问题就出现了。 remove函数使用Node上的CompareTo方法来查找要删除的节点,正如我之前所说,此函数在比较对象时显然没有返回正确的结果。这意味着下面的代码不会在100%的时间内从字典中删除节点。您不能将equalityComparer传递给remove函数,这样就无法修复我的问题。
Node node = new Node(); //It has a grid position and a f value
openList.add(node, false);
openList.Remove(node);
也许我以错误的方式处理这个问题,所以如果有人提出解决这个问题的建议,我会非常乐意听到这些问题。也许我可以写一个解决这个问题的CompareTo函数?
答案 0 :(得分:0)
这个问题可能是您在比较器中比较GridPosition
的结果。
C#区分值类型和引用类型。如果比较两个int
变量,则比较器将基于值进行相等。对于实例化的类,然而comparisson基于引用,这意味着您正在比较对象是否是内存中的对象。
此:
if (GridPosition != other.GridPosition)
{
可能几乎总是返回true,从而导致您的排序顺序正确,因为如果statment嵌套在内部,则提供订单:
if (F > other.F)
{
return 1;
}
if (F < other.F)
{
return -1;
}
但是如果(F == other.F)
指定了-1
,那么ContainsKey将无法将这些对象识别为相等。
根据GridPosition的类型,您应该提供适当的比较器,例如
if (GridPosition.X != other.GridPosition.X && GridPosition.Y != other.GridPosition.Y)
并且取决于F
是什么,你违反了对称的数学原理,因为具有不同GridPosition和等于F的对象将总是在任何其他对象实现之前被排序。因此,对于两个对象,您可以获得A == B ==> -1
和B == A ==> -1
,这在任何情况下都无用。
所以你必须在嵌套的if:
中这样做if (GridPosition != other.GridPosition)
{
if (F > other.F)
{
return 1;
}
if (F < other.F)
{
return -1;
}
/////////////////////////////////
return 0;
/////////////////////////////////
}
或将比较扩展到GridPosition
和F
以外的第三个条件
编辑:根据您在评论中提供的信息,在这种情况下,您实际上并不需要字典,只需要具有正确排序的列表。例如:
List<Node> myList = new List<Node>();
myList.Sort((node1, node2) => node1.F > node2.F);//Sort the list based on their node value
至于你的布尔;我不知道这代表什么,但我强烈的印象是你想要一个常规的Dictionary<Node, bool>
。然后使用列表myList
来处理您需要的任何节点作为下一个航路点,并在需要时查找与字典中的节点相对应的bool。