检查链接列表<node <t >>是否包含某个节点

时间:2018-12-01 21:07:19

标签: c# graph linked-list

我正在使用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);

我的实现有什么问题以及如何解决?

2 个答案:

答案 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。
  • 尝试使用常见的编码样式,以使代码更具可读性。例如,对于属性,我们使用Pascal Case
  • 在这种情况下,您不需要公共设置者。
  • 您不需要默认的构造函数。有人打电话给new Edge<int>()是什么意思?更不用说您会得到一个例外,因为所有属性都将获得对应的默认值(双精度-> 0),并且距离/速度的除法将导致除法为零...
  • 在构造函数内部,我们必须验证所获取的值是否有意义。否则,我们充其量只能使对象处于无意义的状态。没有节点,我们无法拥有优势!因此null既不是源也不是目标的有效值。此外,distancespeed应该大于零。即使speed具有某种意义,distancespeed的划分也将毫无意义-更不用说例外了……

答案 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方法的默认实现,该方法会失败,这就是为什么您会错过多边情况的原因。