我正在使用c#实现Graph,我想检查是否两次插入相同的边,以便在执行此操作时可以抛出异常。
我的班级名字是Graph
这是我对_adjacencyList的声明
protected virtual Dictionary<T, LinkedList<Node<T>>> _adjacencyList { get; set; }
这是我的节点类
class Node<T> where T : IComparable<T>
{
public double speed { get; set; }
public double time { get; set; }
public double distance { get; set; }
public T source { get; set; }
public T destenation { get; set; }
public Node() { }
public Node(T SOURCE, T DESTENATION, double SPEED, double DISTANCE)
{
this.source = SOURCE;
this.destenation = DESTENATION;
this.speed = SPEED;
this.distance = DISTANCE;
this.time = this.distance / this.speed;
}
}
这是我的addEdge函数,它接受源顶点和目标顶点 和值Edge的“重量”
public void addEdge(T source, T Destenation, double speed, double Distance)
{
if (_adjacencyList.Count <= 0)
{
throw new InvalidOperationException("addEdge: There are no Vertices in Graph.\n");
}
else
{
if (_adjacencyList.ContainsKey(source) && _adjacencyList.ContainsKey(Destenation))
{
var sourceEdge = new Node<T>(source, Destenation, speed, Distance);
var destenationEdge = new Node<T>(Destenation, source, speed, Distance);
if (_adjacencyList[source].Contains(sourceEdge) || _adjacencyList[Destenation].Contains(destenationEdge))
{
throw new InvalidOperationException("addEdge: Edge already exists in Graph.\n");
}
else
{
_adjacencyList[source].AddLast(sourceEdge);
_adjacencyList[Destenation].AddLast(destenationEdge);
++_edgeCount;
}
}
else
{
throw new NullReferenceException("addEdge : Source or Destenation Vetrtex Don't Exist in Graph.\n");
}
}
}
当我在main中编写此代码时,不会抛出“图形中已经存在Edge”的异常。
Graph<int> g = new Graph<int>();
g.addVertex(1);
g.addVertex(2);
g.addVertex(3);
g.addVertex(4);
g.addEdge(1,2,15.0,60.0);//Multiple Edge
g.addEdge(1, 2, 15.0, 60.0);//Multiple Edge
g.addEdge(1, 3, 5.0, 40.0);
g.addEdge(2,3,1.0,10.0);
g.addEdge(4,1,2.0,8.0);
我的实现有什么问题以及如何解决?
答案 0 :(得分:3)
发生这种情况是因为您忘记了为类Equals
覆盖Node
方法。
您需要类似以下实现的内容:
public class Edge<T>
{
public double Speed { get; }
public double Time { get; }
public double Distance { get; }
public T Source { get; }
public T Destination { get; }
public Edge(T source, T destination, double speed, double distance)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (destination == null) throw new ArgumentNullException(nameof(destination));
if (Math.Abs(speed) < 1E-9) throw new ArgumentException("speed must greater than zero", nameof(speed));
if (Math.Abs(distance) < 1E-9) throw new ArgumentException("distance must greater than zero", nameof(speed));
Source = source;
Destination = destination;
Speed = speed;
Distance = distance;
Time = Distance / Speed;
}
public override bool Equals(object obj)
{
if (!(obj is Edge<T> objAsEdgeT))
{
return false;
}
return Math.Abs(Speed - objAsNodeT.Speed) < 1E-9
&& Math.Abs(Time - objAsNodeT.Time) < 1E-9
&& Source.Equals(objAsNodeT.Source)
&& Destination.Equals(objAsNodeT.Destination);
}
public override int GetHashCode()
{
unchecked
{
int hash = 13;
hash = (hash*7) + Speed.GetHashCode();
hash = (hash*7) + Time.GetHashCode();
hash = (hash*7) + Source.GetHashCode();
hash = (hash*7) + Destination.GetHashCode();
return hash;
}
}
}
一些注意事项:
Node
本质上表示边缘。因此Edge
将是一个更合适的类名。考虑相反的情况,某人阅读和实际理解与图的节点相关的代码有多困难,而我们选择的名称是edge。
new Edge<int>()
是什么意思?更不用说您会得到一个例外,因为所有属性都将获得对应的默认值(双精度-> 0),并且距离/速度的除法将导致除法为零... null
既不是源也不是目标的有效值。此外,distance
和speed
应该大于零。即使speed
具有某种意义,distance
和speed
的划分也将毫无意义-更不用说例外了……答案 1 :(得分:3)
原因确实是因为您没有为Node类实现Equals方法,因此我也在这里解释原因。
为了理解为什么需要Equals方法,需要了解LinkedList类的工作原理,这很简单,您只需添加,然后删除其中的Node类型的对象即可。到目前为止一切都很好,但是正如您在此代码块中使用此对象一样
if (_adjacencyList[source].Contains(sourceEdge) ...)
{
throw new InvalidOperationException("addEdge: Edge already exists in Graph.\n");
}
您调用包含方法。现在,您的LinkedList对象必须调查它所保存的数据,并尝试比较给定条目是否已在列表中,不幸的是,没有地方提到如何执行此操作,因此它不知道该怎么做。创建LinkedLists的人们对此深有体会,并说:让我们有一种通用的方法来检查两个数据类型是否相等的对象,这就是著名的Equals方法的诞生。
现在您有权说,等等,不是默认情况下每个班级都定义了等于吗?嗯,您是完全正确的,但是,还是有点错,Equals方法的dafault实现对我们不利,因为它会检查对象引用并进行比较。即使您使用相同的数据创建2个对象,它们也会具有不同的引用,并且对它们的Equals方法将失败(显然)。
继续使用链表故事,链表将使用Equals方法的默认实现,该方法会失败,这就是为什么您会错过多边情况的原因。