最短路径链接列表

时间:2013-04-18 05:30:33

标签: java algorithm shortest-path

我想在链表列表中找到最短路径,它表示每条边/路径成本的有向图。

输出看起来像这样,它告诉我从顶点0到其他顶点需要花费的成本:

d[0 to 0] = 0
d[0 to 1] = 20
d[0 to 2] = 10

这就是我填充我的列表进行测试的方式。

LinkedList<GraphData> g = new LinkedList[3];

for (int i = 0; i < 3; i++)
    weight[i] = new LinkedList<GraphData>();

g[0].add(new GraphData(1, 20);
g[0].add(new GraphData(2, 10);

GraphData类看起来像这样:

int vertex, int edgeCost;

现在我的问题:

我想找到从顶点v到所有其他路径的最短路径。

 public static int[] shortestPaths(int v, LinkedList<GraphData>[] cost)
{
    // get the set of vertices
    int n = cost.length;

    // dist[i] is the distance from v to i
    int[] dist = new int[n];

    // s[i] is true if there is a path from v to i
    boolean[] s = new boolean[n];

    // initialize dist
    for(int i = 0; i < n; i++)
        dist[i] = cost[v].get(i).getCost();

    s[v] = true;

    // determine n-1 paths from v 
    for ( int j = 2 ; j < n  ; j++ )
    {
        // choose u such that dist[u] is minimal for all w with s[w] = false
        // and dist[u] < INFINITY
        int u = -1;

        for (int k = 0; k < n; k++)
            if ( !s[k] && dist[k] < INFINITY)
                // check if u needs updating
                if ( u < 0 || dist[k] < dist[u])
                    u = k;
        if (u < 0)
            break; 

        // set s[u] to true and update the distances
        s[u]=true;

        for (int k = 0; k < n; k++)
            if ( !s[k] && cost[u].get(k).getCost() < INFINITY )
                if( dist[k] > dist[u] + cost[u].get(k).getCost())
                    dist[k] = dist[u] + cost[u].get(k).getCost();

        // at this point dist[k] is the smallest cost path from
        // v to k of length j.
    }       
    return dist;
}

此行dist [i] = cost [v] .get(i).getCost();抛出“IndexOutOfBoundsException”

知道我做错了什么吗?任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

表示图表有两种常用方法:邻接列表和邻接矩阵。

邻接列表:列表数组。索引i处的元素是一个包含顶点i的传出边的小列表。这是您填充列表时创建的内容。

邻接矩阵:数组数组,cost[i][j]包含从顶点i到顶点j的边的开销。您正在使用cost参数,就好像它是一个邻接矩阵。

您有两种选择:

  • 更改图形构造以创建邻接矩阵并使用数组数组
  • 更改算法以将cost视为邻接列表而不是邻接矩阵

这是第二种选择。我重命名了一些内容并简化了初始化,以便第一次迭代计算到v的直接邻居的距离(而不是在开始时作为特殊情况)。

import java.util.*;

public class Main
{
    public static int[] shortestPaths(int v, LinkedList<Edge>[] edges)
    {
        // get the set of vertices
        int n = edges.length;

        // dist[i] is the distance from v to i
        int[] dist = new int[n];
        for (int i = 0; i < n; i++) {
            dist[i] = Integer.MAX_VALUE;
        }

        // seen[i] is true if there is a path from v to i
        boolean[] seen = new boolean[n];

        dist[v] = 0;

        // determine n-1 paths from v
        for (int j = 0; j < n; j++) {
            // choose closest unseen vertex
            int u = -1;

            for (int k = 0; k < n; k++) {
                if (!seen[k]) {
                    // check if u needs updating
                    if (u < 0 || dist[k] < dist[u]) {
                        u = k;
                    }
                }
            }

            if (u < 0 || dist[u] == Integer.MAX_VALUE) {
                break;
            }

            // at this point dist[u] is the cost of the
            // shortest path from v to u

            // set seen[u] to true and update the distances
            seen[u] = true;

            for (Edge e : edges[u]) {
                int nbr = e.getTarget();
                int altDist = dist[u] + e.getCost();
                dist[nbr] = Math.min(dist[nbr], altDist);
            }
        }

        return dist;
    }

    public static void main(String[] args)
    {
        int n = 5;
        int start = 0;
        LinkedList<Edge>[] cost = new LinkedList[n];
        for (int i = 0; i < n; i++) {
            cost[i] = new LinkedList<Edge>();
        }

        cost[0].add(new Edge(1, 20));
        cost[0].add(new Edge(2, 10));
        cost[1].add(new Edge(3, 5));
        cost[2].add(new Edge(1, 6));

        int[] d = shortestPaths(start, cost);
        for (int i = 0; i < n; i++) {
            System.out.print("d[" + start + " to " + i + "] = ");
            System.out.println(d[i]);
        }
    }
}

class Edge
{
    int target, cost;

    public Edge(int target, int cost) {
        this.target = target;
        this.cost = cost;
    }

    public int getTarget() {
        return target;
    }

    public int getCost() {
        return cost;
    }
}

答案 1 :(得分:0)

可能元素cost[v].get(i)不存在(此i中没有LinkedList的索引为cost[v]的元素。{/ p>

http://docs.oracle.com/javase/6/docs/api/java/util/LinkedList.html#get(int)

答案 2 :(得分:0)

问题是您的指数不对应。如果你只放一个距离,例如

cost[0].add(new GraphData(5, 20));

然后

cost[0].get(5).getCost();

会抛出IndexOutOfBoundsException,因为你应该这样做

cost[0].get(0).getCost();

以获得20(这非常令人困惑)。

我建议使用Map而不是List来编码边缘费用。

您填充Map喜欢

List<Map<Integer, Integer>> g = new ArrayList<>();

for (int i = 0; i < 3; i++)
    g.add(new HashMap<Integer, Integer>());

g.get(0).put(1, 20);
g.get(0).put(2, 10);

有了这个,您可以初始化dist数组,如

// initialize dist
for(int i = 0; i < n; i++)
    dist[i] = cost.get(v).containsKey(i) ? cost.get(v).get(i) : INFINITY;