Dijkstra的Dilema:我怎样才能使我的算法抽象化?

时间:2014-10-04 01:19:17

标签: java algorithm graph dijkstra shortest-path

我正在做代码强制,并希望使用带有邻接矩阵的Java实现Dijkstra的最短路径算法,但是我很难使其适用于其他大小而不是它的大小。编码处理。

这是我的工作代码

int max = Integer.MAX_VALUE;//substitute for infinity

    int[][] points={//I used -1 to denote non-adjacency/edges
            //0, 1, 2, 3, 4, 5, 6, 7
            {-1,20,-1,80,-1,-1,90,-1},//0
            {-1,-1,-1,-1,-1,10,-1,-1},//1
            {-1,-1,-1,10,-1,50,-1,20},//2
            {-1,-1,-1,-1,-1,-1,20,-1},//3
            {-1,50,-1,-1,-1,-1,30,-1},//4
            {-1,-1,10,40,-1,-1,-1,-1},//5
            {-1,-1,-1,-1,-1,-1,-1,-1},//6
            {-1,-1,-1,-1,-1,-1,-1,-1} //7
            };
    int [] record = new int [8];//keeps track of the distance from start to each node
    Arrays.fill(record,max);
    int sum =0;int q1 = 0;int done =0;
    ArrayList<Integer> Q1 = new ArrayList<Integer>();//nodes to transverse 
    ArrayList<Integer> Q2 = new ArrayList<Integer>();//nodes collected while transversing
    Q1.add(0);//starting point
    q1= Q1.get(0);
    while(done<9) {// <<< My Problem
        for(int q2 = 1; q2<8;q2++) {//skips over the first/starting node
            if(points[q1][q2]!=-1) {//if node is connected by an edge
                if(record[q1] == max)//never visited before
                    sum=0;
                else 
                    sum=record[q1];//starts from where it left off
                int total = sum+points[q1][q2];//total distance of route
                if(total < record[q2])//connected node distance
                    record[q2]=total;//if smaller
                Q2.add(q2);//colleceted node
            }
        }
        done++;
        Q1.remove(0);//removes the first node because it has just been used
        if(Q1.size()==0) {//if there are no more nodes to transverse
            Q1=Q2;//Pours all the collected connecting nodes to Q1
            Q2= new ArrayList<Integer>();
            q1=Q1.get(0);
        }
        else//
            q1=Q1.get(0);//sets starting point 
    }![enter image description here][1]

但是,我的算法版本才有效,因为我将while循环设置为已解决的答案。所以换句话说,它只适用于这个问题/图表,因为我先用手解决了

我怎么能这样做才能适用于各种规模的群体?

以下是我的问题基于的示例图表的图形表示:

Image

1 个答案:

答案 0 :(得分:1)

我认为你要找的主要答案是你应该让while循环运行直到Q1为空。你正在做的事情本质上是最好的搜索。但是,由于您的代码有点不正统,因此需要进行更多更改。

通常,Dijkstra的算法与优先级队列一起使用。 Q1是您的&#34;待办事项列表&#34;据我所知,你的代码。 Dijkstra的规范说明接下来应该探索最接近起始顶点的顶点,因此不应该使用ArrayList,而是应该使用Q1的PriorityQueue,根据最接近起始顶点的顶点对顶点进行排序。最常见的Java实现将PriorityQueue与元组类一起使用:一个内部类,它存储对顶点的引用和&#34;距离&#34;到起始顶点。 Dijkstra的规范还规定,如果发现一个新的边缘使顶点更靠近起点,则应该在优先级队列中的条目上使用DecreaseKey操作,以使顶点更早出现(因为它现在更近了)。但是,由于PriorityQueue不支持该操作,因此只会在队列中添加一个全新的条目。如果你有一个支持这个操作的堆的良好实现(我自己创建了一个,here),那么reduceKey可以显着提高效率,因为你不再需要创建那些元组。

所以我希望这是一个足够的答案:做一个合适的&#39; todo&#39; list而不是Q1,为了使算法通用,让while循环运行直到todo列表为空。

编辑:我根据您的格式制作了一个实现,似乎有效:

public void run() {
    final int[][] points = { //I used -1 to denote non-adjacency/edges
        //0, 1, 2, 3, 4, 5, 6, 7
        {-1,20,-1,80,-1,-1,90,-1}, //0
        {-1,-1,-1,-1,-1,10,-1,-1}, //1
        {-1,-1,-1,10,-1,50,-1,20}, //2
        {-1,-1,-1,-1,-1,-1,20,-1}, //3
        {-1,50,-1,-1,-1,-1,30,-1}, //4
        {-1,-1,10,40,-1,-1,-1,-1}, //5
        {-1,-1,-1,-1,-1,-1,-1,-1}, //6
        {-1,-1,-1,-1,-1,-1,-1,-1}  //7
    };
    final int[] result = dijkstra(points,0);
    System.out.print("Result:");
    for(final int i : result) {
        System.out.print(" " + i);
    }
}

public int[] dijkstra(final int[][] points,final int startingPoint) {
    final int[] record = new int[points.length]; //Keeps track of the distance from start to each vertex.
    final boolean[] explored = new boolean[points.length]; //Keeps track of whether we have completely explored every vertex.
    Arrays.fill(record,Integer.MAX_VALUE);
    final PriorityQueue<VertexAndDistance> todo = new PriorityQueue<>(points.length); //Vertices left to traverse.
    todo.add(new VertexAndDistance(startingPoint,0)); //Starting point (and distance 0).
    record[startingPoint] = 0; //We already know that the distance to the starting point is 0.
    while(!todo.isEmpty()) { //Continue until we have nothing left to do.
        final VertexAndDistance next = todo.poll(); //Take the next closest vertex.
        final int q1 = next.vertex;
        if(explored[q1]) { //We have already done this one, don't do it again.
            continue; //...with the next vertex.
        }

        for(int q2 = 1;q2 < points.length;q2++) { //Find connected vertices.
            if(points[q1][q2] != -1) { //If the vertices are connected by an edge.
                final int distance = record[q1] + points[q1][q2];
                if(distance < record[q2]) { //And it is closer than we've seen so far.
                    record[q2] = distance;
                    todo.add(new VertexAndDistance(q2,distance)); //Explore it later.
                }
            }
        }

        explored[q1] = true; //We're done with this vertex now.
    }
    return record;
}

private class VertexAndDistance implements Comparable<VertexAndDistance> {
    private final int distance;
    private final int vertex;

    private VertexAndDistance(final int vertex,final int distance) {
        this.vertex = vertex;
        this.distance = distance;
    }

    /**
     * Compares two {@code VertexAndDistance} instances by their distance.
     * @param other The instance with which to compare this instance.
     * @return A positive integer if this distance is more than the distance
     * of the specified object, a negative integer if it is less, or
     * {@code 0} if they are equal.
     */
    @Override
    public int compareTo(final VertexAndDistance other) {
        return Integer.compare(distance,other.distance);
    }
}

输出:0 20 40 50 2147483647 30 70 60