Arhn - архитектура программирования

Проверить, содержит ли связанный список‹Узел‹T›› определенный узел

Я реализую 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, которая принимает исходную вершину и вершину назначения и значения «Вес» края.

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».

   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);

Что не так с моей реализацией и как это исправить?

01.12.2018

Ответы:


1

Это происходит потому, что вы забыли переопределить метод 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 было бы более подходящим именем класса. Подумайте об обратном: как трудно кому-то было бы прочитать и на самом деле понять фрагмент кода, связанный с узлами графа, и имя, которое мы выбрали, — ребро.
  • Старайтесь использовать общие стили кодирования, чтобы ваш код был более читабельным. Например, для свойств мы используем Дело Паскаля.
  • В этом случае вам не нужны общедоступные сеттеры.
  • Вам не нужен конструктор по умолчанию. Какой смысл в том, что кто-то звонит new Edge<int>()? Не говоря уже о том, что вы получите исключение, поскольку все свойства получат соответствующие значения по умолчанию (двойное -> 0), а расстояние/скорость деления приведет к делению с нулем...
  • Внутри конструктора мы должны убедиться, что получаемые нами значения имеют смысл. В противном случае мы получим объект в лучшем случае в бессмысленном состоянии. У нас не может быть ребра без узлов! Таким образом, null не является допустимым значением ни для источника, ни для пункта назначения. Кроме того, distance и speed должны быть больше нуля. Даже если бы speed имело какое-то значение, деление на distance и speed было бы бессмысленным, не говоря уже об исключении...
01.12.2018

2

Причина действительно в том, что вы не реализовали метод Equals для класса Node, и я здесь, чтобы объяснить, почему.

Для того, чтобы понять, зачем вам нужен метод Equals, вам нужно понять, как работает класс LinkedList, который довольно прост: вы просто добавляете, а затем удаляете в нем объекты типа Node. Пока все хорошо, но поскольку вы используете этот объект в этом блоке кода
if (_adjacencyList[source].Contains(sourceEdge) ...) { throw new InvalidOperationException("addEdge: Edge already exists in Graph.\n"); }
, вы вызываете метод Contains. Теперь ваш объект LinkedList должен изучить данные, которые он содержит, и попытаться сравнить, если данная запись уже находится в списке, к сожалению, нигде не упоминается, как это сделать, поэтому он не знает, что делать. Хорошо, что люди, создавшие LinkedLists, подумали об этом и сказали: давайте иметь общий способ проверки равенства двух объектов любого типа данных, и именно так родился знаменитый метод Equals.
Теперь вы имеете право на это. скажем, подождите, разве Equals не определен по умолчанию для каждого класса? Ну, вы абсолютно правы, это так, но также и неправильно, реализация метода Equals по умолчанию не годится для нас, поскольку она проверяет ссылки на объекты и сравнивает их. Даже если вы создадите 2 объекта с одинаковыми данными, они будут иметь разные ссылки, и метод Equals для них не сработает (очевидно).

Продолжая историю связанного списка, связанный список будет использовать реализацию метода Equals по умолчанию, которая дает сбой, и поэтому вы пропустите случай множественных краев.

01.12.2018
  • поскольку вы сначала обратились к части «почему», вы определенно заслуживаете +1. 02.12.2018
  • Как насчет Как проверить, является ли граф узел находится в пункте назначения в LinkedList?? 12.06.2020
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..