0

隣接リストと行列の両方の実装を持つグラフ ライブラリを作成しています。Javaデータ構造の教科書で見つけたコードを次に示します。

static void floyd(Graph<V,E> g) 
// post: g contains edge (a,b) if there is a path from a to b 
{
     Iterator<V> witer = g.iterator();   //vertex iterator
     while (witer.hasNext())
     {
        Iterator<V> uiter = g.iterator(); 
        V w = witer.next(); 
        while (uiter.hasNext())
        {
            Iterator<V> viter = g.iterator();
            V u = uiter.next(); 
            while (viter.hasNext())
            {
                V v = viter.next(); 
                if (g.containsEdge(u,w) && g.containsEdge(w,v)) 
                {
                     Edge<V,E> leg1 = g.getEdge(u,w);
                     Edge<V,E> leg2 = g.getEdge(w,v); 
                     int leg1Dist = leg1.label(); 
                     int leg2Dist = leg2.label(); 
                     int newDist = leg1Dist+leg2Dist;

                     if (g.containsEdge(u,v)) 
                     {
                         Edge<V,E> across = g.getEdge(u,v); 
                         int acrossDist = across.label(); 
                         if (newDist < acrossDist)
                           across.setLabel(newDist); 
                      } 
                      else 
                      {
                           g.addEdge(u,v,newDist);
                       }
                  }
             }
         }
     }

しかし、現在のエッジを「最短」で上書きしているようです。この解釈は正しいでしょうか?ここでいくつかの説明を使用できます。

注: Edge クラスの一部を次に示します。

public class Edge
{
/**
 * Two element array of vertex labels.
 * When necessary, first element is source.
 */
protected Object[] vLabel;  // labels of adjacent vertices
/**
 * Label associated with edge.  May be null.
 */
protected Object label;     // edge label
/**
 * Whether or not this edge has been visited.
 */
protected boolean visited;  // this edge visited
/**
 * Whether or not this edge is directed.
 */
protected boolean directed; // this edge directed

/**
 * Construct a (possibly directed) edge between two labeled
 * vertices.  When edge is directed, vtx1 specifies source.
 * When undirected, order of vertices is unimportant.  Label
 * on edge is any type, and may be null.
 * Edge is initially unvisited.
 *
 * @post edge associates vtx1 and vtx2; labeled with label
 *       directed if "directed" set true
 *
 * @param vtx1 The label of a vertex (source if directed).
 * @param vtx2 The label of another vertex (destination if directed).
 * @param label The label associated with the edge.
 * @param directed True iff this edge is directed.
 */
public Edge(Object vtx1, Object vtx2, Object label,
            boolean directed)
{
    vLabel = new Object[2];
    vLabel[0] = vtx1;
    vLabel[1] = vtx2;
    this.label = label;
    visited = false;
    this.directed = directed;
}

/**
 * Returns the first vertex (or source if directed).
 *
 * @post returns first node in edge
 * 
 * @return A vertex; if directed, the source.
 */
public Object here()
{
    return vLabel[0];
}

/**
 * Returns the second vertex (or source if undirected).
 *
 * @post returns second node in edge
 * 
 * @return A vertex; if directed, the destination.
 */
public Object there()
{
    return vLabel[1];
}

/**
 * Sets the label associated with the edge.  May be null.
 *
 * @post sets label of this edge to label 
 * 
 * @param label Any object to label edge, or null.
 */
public void setLabel(Object label)
{
    this.label = label;
}

/**
 * Get label associated with edge.
 *
 * @post returns label associated with this edge
 * 
 * @return The label found on the edge.
 */
public Object label()
{
    return label;
}
4

1 に答える 1

4

行列を使用して結果を行列に格納すると、何をしているのかを理解しやすくなります。次の単純な加重グラフを考えてみましょう。

       2
1 +---------+ 2
  |\        |
  | -\      |
3 |   -\5   | 2
  |     -\  |
  |       -\|
3 +---------+ 4
        4

ここで、 Floyd-Warshall アルゴリズムのこの実装について考えてみましょう。

public Matrix floyd() {
  Matrix m = new Matrix(numVertices, numVertices, Integer.MAX_VALUE);
  for (int i = 1; i<=numVertices; i++) {
    EdgeNode edge = edges[i];
    while (edge != null) {
      m.setData(i, edge.getY(), edge.getWeight());
      edge = edge.getNext();
    }
    m.setData(i, i, 0);
  }
  for (int i = 1; i <= numVertices; i++) {
    for (int j = 1; j <= numVertices; j++) {
      for (int k = 1; k <= numVertices; k++) {
        if (m.getData(i, j) < Integer.MAX_VALUE && m.getData(i, k) < Integer.MAX_VALUE) {
          int through = m.getData(i, j) + m.getData(i, k);
          if (through < m.getData(j, k)) {
            m.setData(j, k, through);
          }
        }
      }
    }
  }
  return m;
}

この最初の部分は、行列の結果に をシードしInteger.MAX_VALUEます。ここに 0 を入れると間違った結果が得られますが、1 と 0 の値を (それぞれ) 使用すると、重み付けされていないグラフでは問題なく機能します。Integer.MAX_VALUE正しい最小値チェックのためだけに存在します。

2 番目の部分は、アルゴリズムの重要な部分です。2 点 (i,k) 間の距離を調べ、すべての頂点 j の (i,j) + (j,K) の距離と比較します。間接パスがそれより小さい場合は、最短パスなどとしてマトリックスに代入されます。

上記の(非常に単純な)グラフでのこのアルゴリズムの結果は次のとおりです。

[ 0 2 3 5 ]
[ 2 0 5 3 ]
[ 3 5 0 4 ]
[ 5 3 4 0 ]

これは、頂点の任意のペア間の最短距離を示しています。注: (i,i) の結果を 0 にシードしました。これは、任意のノードからそれ自体までの距離は 0 であると主張できるためです。その仮定を十分に簡単に取り出すことができ、この結果が得られます。

[ 4 2 3 5 ]
[ 2 4 5 3 ]
[ 3 5 6 4 ]
[ 5 3 4 6 ]

したがって、ノード 3 からそれ自体までの距離は 6 で、最短パスとして 3->1->3 を通過します。これは、Floyd が処理できる有向グラフではさらに興味深いものになります。

Floyd のアルゴリズムは O(n 3 ) アルゴリズムです。ポイントの各ペア間の実際のパスを再構築するのではなく、合計距離 (重み) のみを再構築します。各頂点ペア間でDijkstra のアルゴリズムを使用して実際のパスを構築できます。興味深いことに、これも O(n 3 ) ですが、Floyd の計算は非常に単純であるため、実際の使用では遅くなる傾向があります。

あなたのアルゴリズムは、行列の代わりに隣接リストを使用してこのアルゴリズムを実装しているため、問題が少し混乱します。私のバージョンはInteger.MAX_VALUEセンチネル値として使用してパスがないことを示します(まだ計算されています)が、あなたのものは同じことのエッジがないことを使用しています。それ以外は、まったく同じです。

于 2010-07-15T04:11:08.123 に答える