Java: Как выглядит мой Прим?

Я пытаюсь реализовать алгоритм минимального связующего дерева Prim с помощью JGraphT. Как это выглядит?

Одна проблема, с которой я столкнулся, заключалась в том, что JGraphT обрабатывает все, как указано. Поэтому иногда необходимо сделать несколько неудобных вызовов, чтобы поменять местами g.getEdgeSource(e) и g.getEdgeTarget(e), если они оказались неверными.

Первоначально я пытался реализовать это с помощью кучи Фибоначчи JGraphT, но это было слишком сложно, поэтому я просто сделал обычный PQ.

Вместо того, чтобы устанавливать веса несуществующих ребер на бесконечность, я просто не добавлял их в очередь.

Совет? Проблемы со стилем? Вопиющая неэффективность? Код, который я должен использовать вместо собственного?

public static Graph<String, DefaultWeightedEdge> primPQ(final WeightedGraph<String, DefaultWeightedEdge> g, String root) {
  Graph<String, DefaultWeightedEdge> mst = new SimpleWeightedGraph<String, DefaultWeightedEdge>(DefaultWeightedEdge.class);
  Queue<DefaultWeightedEdge> pq = new PriorityQueue<DefaultWeightedEdge>(g.vertexSet().size(), new Comparator<DefaultWeightedEdge>() {
    @Override
    public int compare(DefaultWeightedEdge o1, DefaultWeightedEdge o2) {
      if (g.getEdgeWeight(o1) < g.getEdgeWeight(o2)) {
        return -1;
      }
      if (g.getEdgeWeight(o1) > g.getEdgeWeight(o2)) {
        return 1;
      } 
      return 0;
    }
  });

  mst.addVertex(root);
  DefaultWeightedEdge link;

  for (String v : g.vertexSet()) {
    link = g.getEdge(root, v);
    if (link != null) {
      pq.add(link);
    }
  }

  //this is made difficult by JGraphT's assumption that everything is directed
  DefaultWeightedEdge minEdge = pq.poll();
  String toAdd;
  String alreadyFound;
  String tmp;

  while (minEdge != null) {
    // guessing at which is in the MST
    toAdd = g.getEdgeTarget(minEdge);
    alreadyFound = g.getEdgeSource(minEdge);

    if (!(mst.containsVertex(toAdd) && mst.containsVertex(alreadyFound))) {
      // swap if backwards
      if (mst.containsVertex(toAdd)) {
        tmp = toAdd;
        toAdd = alreadyFound;
        alreadyFound = tmp;
      }
      mst.addVertex(toAdd);
      mst.addEdge(alreadyFound, toAdd, minEdge);
      System.out.format("%s --> %s\n", g.getEdgeSource(minEdge), toAdd);

      for (String v : g.vertexSet()) {
        if (! mst.containsVertex(v)) {
          link = g.getEdge(toAdd, v);
          if (pq.contains(link)) {
            g.setEdgeWeight(minEdge, Math.min(g.getEdgeWeight(minEdge), g.getEdgeWeight(link)));
          }
          if (link != null && ! pq.contains(link)) {
            pq.add(link);
          }
        }
      }
    }
    minEdge = pq.poll();
  }
  return mst;
}

person Nick Heiner    schedule 24.11.2009    source источник
comment
На самом деле не смотрел весь этот код, но AFAIK JGraphT явно поддерживает неориентированные графы jgrapht. org/javadoc/org/jgrapht/UndirectedGraph.html   -  person jitter    schedule 24.11.2009
comment
да, но тогда, учитывая преимущество, как получить две конечные точки?   -  person Nick Heiner    schedule 24.11.2009


Ответы (3)


Я сравнил результат вашего алгоритма с одним моим, который был домашним заданием, и оба они дают одинаковый минимальный общий вес, так держать!

person simonarame    schedule 10.10.2010

И при увеличении количества ребер, и при увеличении количества вершин я получаю разные результаты, я вернусь...

person simonarame    schedule 10.10.2010
comment
Так что этикет предпочел бы, чтобы вы отредактировали свой исходный ответ, а не делали больше. :) - person Nick Heiner; 10.10.2010

ОКЕЙ, теперь все выглядит хорошо.

Кстати, мое упражнение было немного сложным: мне нужно было написать алгоритм, который действительно находит минимальное остовное дерево, но мой алгоритм должен был действовать методом исключения на ребрах. Я написал что-то, что использует некоторый обход в глубину для поиска циклов, а затем устраняет наиболее взвешенное ребро, «окрашивая» его в красный цвет.

Ваш алгоритм PRIM дает тот же минимальный общий вес, что и мой алгоритм для 4 случайно сгенерированных графов, которые имеют N = 200 узлов и различные значения M = (N * (N-1)/k) для k = 2,3,4,8 для количество ребер.

На первый взгляд, я бы подумал, что такое тестирование было излишним, но это не так!

person simonarame    schedule 10.10.2010