Реализуйте косвенный тест подключения для класса Java Graph

StackOverflow https://stackoverflow.com/questions/3551083

Вопрос

Я пишу класс в Java, чтобы представлять структуру данных графа. Это специфично для непраркому, невосприимчивому графику, и ее цель в основном предназначено для краевого тестирования (является узлом a подключен к узлу B, либо прямо или косвенно).

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

Я поставил некоторое время придумать алгоритм, но я не могу найти все более простое, чем это, и я боюсь, что я делаю его более сложным, чем это должно быть:

  • Проверьте сначала для прямого соединения
  • Если не существует прямое соединение из узла A до узла B:
    • Для каждого края я подключался к узлу A:
      • Создайте новый график, который не содержит Edge A -> I
      • Проверьте новый график для косвенного подключения между узлами I и B

Либо псевдокод или фактический код Java приветствуется в ваших ответах. Вот код у меня есть:

class Graph {

    // This is for an undirected, unweighted graph
    // This implementation uses an adjacency matrix for speed in edge testing 

    private boolean[][] edge;
    private int numberOfNodes;

    public Graph(int numNodes) {

        // The indices of the matrix will not be zero-based, for clarity,
        // so the size of the array will be increased by 1.

           edge = new boolean[numNodes + 1][numNodes + 1];
           numberOfNodes = numNodes;
    }

    public void addEdge(int a, int b) {
        if (a <= numberOfNodes && a >= 1) {
            if (b <= numberOfNodes && b >= 1) {
                edge[a][b] = true;
                edge[b][a] = true;
            }
        }
    }

    public void removeEdge(int a, int b) {
        if (a <= numberOfNodes && a >= 1) {
            if (b <= numberOfNodes && b >= 1) {
                edge[a][b] = false;
                edge[b][a] = false;
            }
        }
    }

    public boolean directEdgeTest(int a, int b) {

        // if node a and node b are directly connected, return true 

        boolean result = false;
        if (a <= numberOfNodes && a >= 1) {
            if (b <= numberOfNodes && b >= 1) {
                if (edge[a][b] == true) {
                    result = true;
                }
            }
        }
        return result;
    }

    public boolean indirectEdgeTest(int a, int b) {

        // if there exists a path from node a to node b, return true 

            // implement indirectEdgeTest algorithm here.

            return false;
    }
}
Это было полезно?

Решение 3

Я кредитую меритону за свой ответ, но я закодировал идею работы Java-классов и тестирование подразделения, поэтому я предоставляющую отдельный ответ здесь, если кто-либо ищет многоразовый код.

Спасибо Meriton. Я согласен, что важно сделать различие между тестированием прямого края и тестирование на пути, и что существуют различные реализации графов, которые лучше подходят для конкретного типа тестирования. В случае тестирования на пути, кажется, списки соседних гораздо более эффективны, чем представление матрицы соседних.

Мой код ниже, вероятно, не такой эффективный, как могло бы быть, но на данный момент решает мою проблему. Если у кого-то есть улучшения, чтобы предложить, пожалуйста, не стесняйтесь.

Для компиляции: Javac Graph.java

Выполнить: Java Graphtest

class Graph {

    private java.util.ArrayList<Node> nodeList;
    private int numberOfNodes;

    public Graph(int size) {
        nodeList = new java.util.ArrayList<Node>(size + 1);
        numberOfNodes = size;

        for (int i = 0; i <= numberOfNodes; i++) {
            nodeList.add(new Node());
        }
    }

    public void addEdge(int a, int b) {
        if (a >= 1 && a <= numberOfNodes) {
            if (b >= 1 && b <= numberOfNodes) {
                nodeList.get(a).addNeighbour(nodeList.get(b));
                nodeList.get(b).addNeighbour(nodeList.get(a));
            }
         }
    }

    public void walk(Node origin, java.util.Set<Node> visited) {
        for (Node n : origin.getNeighbours()) {
            if (!visited.contains(n)) {
                visited.add(n);
                walk(n, visited);
            }
        }
    }

    public boolean hasPath(Node origin, Node target) {
        java.util.Set<Node> reachables = new java.util.HashSet<Node>();
        walk(origin, reachables);
        return reachables.contains(target);
    }

    public boolean hasPath(int a, int b) {

        java.util.Set<Node> reachables = new java.util.HashSet<Node>();
        Node origin = nodeList.get(a);
        Node target = nodeList.get(b);
        walk(origin, reachables);
        return reachables.contains(target);       
    }
}

class Node {

    private java.util.Set<Node> neighbours;

    public Node() {
        neighbours = new java.util.HashSet<Node>();
    }

    public void addNeighbour(Node n) {
        neighbours.add(n);
    }

    public java.util.Set<Node> getNeighbours() {
        return neighbours;
    }
}

class GraphTest {

    private static Graph g;

    public static void main(String[] args) {

        g = new Graph(6);

        g.addEdge(1,5);
        g.addEdge(4,1);
        g.addEdge(4,3);
        g.addEdge(3,6);

        printTest(1, 2);
        printTest(1, 4); 
        printTest(6, 1);   
    }

    public static void printTest(int a, int b) {

        System.out.print("Are nodes " + a + " and " + b + " connected?");
        if (g.hasPath(a, b)) {
            System.out.println(" YES.");
        } else {
            System.out.println(" NO.");
        }
    }
}

Другие советы

ERM, этот подход звучит ужасно неэффективно. Как насчет этого:

void walk(Node orgin, Set<Node> visited) {
    for (Node n : origin.neighbours) {
        if (!visited.contains(n)) {
            visited.add(n);
            walk(n, visited);
        }
    }
}


boolean hasPath(Node origin, Node target) {
    Set<Node> reachables = new HashSet<Node>();
    walk(origin, reachables);
    return reachables.contains(target);
}

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

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

Редактировать: чтобы уточнить, как лучше всего представлять график. Для тестирования прямого края предпочтительнее матрица смежности. Для тестирования пути разложение в регионы. Последнее не тривиально, чтобы удерживать ток, как графические изменения, но могут быть алгоритмы для этого в литературе. Альтернативно, списки соседних обслуживаются для обхода графика и, таким образом, тестирование пути, но они остаются менее эффективными, чем непосредственно записывая разложение в связанные регионы. Вы также можете использовать наборы смежности для сочетания более эффективной итерации соседей в редких графиках с постоянным временем тестирования.

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

Ваше решение будет работать, но лучшее решение было бы созданию охватного дерева из корня «А» узел. Таким образом, вы в конечном итоге у вас будет только одно дерево, вместо нескольких подматочек, которые только отсутствуют определенные края.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top