带权有向图(最短路径算法Dijkstra算法)

本文转载自chinaunix
 
数据结构——带权有向图(最短路径算法Dijkstra算法)
 
1.Dijkstra

1)      适用条件&范围:

a)       单源最短路径(从源点s到其它所有顶点v);

b)       有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图)

c)       所有边权非负(任取(i,j)∈E都有Wij≥0);

2)      算法描述:

a)       初始化:dis[v]=maxint(v∈V,v≠s); dis[s]=0; pre[s]=s; S={s};

b)       For i:=1 to n

1.取V-S中的一顶点u使得dis[u]=min{dis[v]|v∈V-S}

2.S=S+{u}

3.For V-S中每个顶点v do Relax(u,v,Wu,v)

c)       算法结束:dis[i]为s到i的最短距离;pre[i]为i的前驱节点

3)      算法优化:

    使用二叉堆(Binary Heap)来实现每步的DeleteMin(ExtractMin,即算法步骤b中第1步)操作,算法复杂度从O(V^2)降到O((V+E)㏒V)。推荐对稀疏图使用。

    使用Fibonacci Heap(或其他Decrease操作O(1),DeleteMin操作O(logn)的数据结构)可以将复杂度降到O(E+V㏒V);如果边权值均为不大于C的正整数,则使用Radix Heap可以达到O(E+V㏒C)

下面给出Java实现的源码:

package zieckey.datastructure.study.graph;

/**
 *
 * 带权重有方向图
 * 介绍了Dijkstra算法:最短路径算法
 *
 * Dijkstra算法原理:
 *     1) 适用条件&范围:
        a) 单源最短路径(从源点s到其它所有顶点v);
        b) 有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图)
        c) 所有边权非负(任取(i,j)∈E都有Wij≥0);
    2) 算法描述:
        a) 初始化:dis[v]=maxint(v∈V,v≠s); dis[s]=0; pre[s]=s; S={s};
        b) For i:=1 to n
                1.取V-S中的一顶点u使得dis[u]=min{dis[v]|v∈V-S}
                2.S=S+{u}
                3.For V-S中每个顶点v do Relax(u,v,Wu,v)
        c) 算法结束:dis[i]为s到i的最短距离;pre[i]为i的前驱节点
    3) 算法优化:
        a) 使用二叉堆(Binary Heap)来实现每步的DeleteMin(ExtractMin,即算法步骤b中第1步)操作,算法复杂度从O(V^2)降到O((V+E)㏒V)。推荐对稀疏图使用。
        b) 使用Fibonacci Heap(或其他Decrease操作O(1),DeleteMin操作O(logn)的数据结构)可以将复杂度降到O(E+V㏒V);如果边权值均为不大于C的正整数,则使用Radix Heap可以达到O(E+V㏒C)。
 *
 *
 * @author zieckey
 *
 */

public class WeightedDirectedGraph
{
    private final int            MAX_VERTS    = 20;
    private final int            INFINITY    = 1000000;
    private Vertex[]            vertexList;            // list of vertices

    private int[][]                adjMat;                // adjacency matrix

    private int                    nVerts;                // current number of vertices

    private int                    nTree;                    // number of verts in tree

    private DistanceParent[]    shortestPath;                    // array for shortest-path data

    private int                    currentVertex;            // current vertex

    private int                    startToCurrentDistance;        // distance to currentVert

    
    public WeightedDirectedGraph()
    {
        vertexList = new Vertex[MAX_VERTS];
        // adjacency matrix

        adjMat = new int[MAX_VERTS][MAX_VERTS];
        nVerts = 0;
        nTree = 0;
        for ( int j = 0; j < MAX_VERTS; j++ )
        {
            // set adjacency

            for ( int k = 0; k < MAX_VERTS; k++ )
            {
                adjMat[j][k] = INFINITY;
            }
        }
        
        shortestPath = new DistanceParent[MAX_VERTS]; // shortest paths

        
    }

    /**
     * 求最短路径算法:Dijkstra算法。
     */

    public void findShortestPath()
    {
        int startTree = 0;//从0节点开始

        vertexList[startTree].isInTree = true;//将该节点放入树中

        nTree = 1;
        
        //初始化最短路径表,以邻接矩阵中的 startTree 行数据初始化

        for ( int i = 0; i < nVerts; i++ )
        {
            shortestPath[i] = new DistanceParent( startTree, adjMat[startTree][i] );
        }
        
        while( nTree < nVerts )
        {
            int indexMin = getMinFromShortestPath();// 从最短路径表中得到目前的最小值

            int minDist = shortestPath[indexMin].distance;
            
            if ( minDist == INFINITY ) // 如果为 INFINITY ,表明不可达,或者都在树中了。

            {
                System.out.println( "There are unreachable vertices" );
                break; // sPath is complete

            } else
            {
                currentVertex = indexMin; // 将最小的赋值给currentVert,为即将进入树中作准备

                startToCurrentDistance = shortestPath[indexMin].distance;//路径权重最小

            }
            // 将当前节点放入树中

            vertexList[currentVertex].isInTree = true;
            nTree++;
            adjust_sPath(); // 更新最短路径表

        }//end while

        
        displayPaths(); // display sPath[] contents

        
        nTree = 0; // clear tree

        for(int j=0; j<nVerts; j++)
        {
            vertexList[j].isInTree = false;
        }
    }
    
    /**
     * 显示最短路径
     */

    public void displayPaths()
    {
        for ( int j = 0; j < nVerts; j++ ) // display contents of sPath[]

        {
            System.out.print( vertexList[j].label + "=" ); // B=

            if ( shortestPath[j].distance == INFINITY )
            {
                System.out.print( "inf" ); // inf

            }
            else
            {
                System.out.print( shortestPath[j].distance ); // 50

            }
            char parent = vertexList[shortestPath[j].parentVert].label;
            System.out.print( "(" + parent + ") " ); // (A)

        }
        System.out.println( "" );
    }

    /**
     * 更新最短路径表
     */

    public void adjust_sPath()
    {
        for ( int column=1; column < nVerts;column++ )//跳过自身,从1开始

        {
            if ( false == vertexList[column].isInTree )//如果不在树中

            {
                // calculate distance for one sPath entry

                
                
                int currentToFringe = adjMat[currentVertex][column];// 当前点到column的距离

                int startToFringe = startToCurrentDistance + currentToFringe;//计算起始点到column的距离

                
                // 与原来最短路径表中的权重值进行比较

                if ( startToFringe < shortestPath[column].distance ) // 如果新值更小,就更新最短路径表

                {
                    shortestPath[column].parentVert = currentVertex;
                    shortestPath[column].distance = startToFringe;
                }//end if

            }//end if

        }//end for

    }

    /**
     * 从最短路径表中得到目前的最小值
     * @return 返回最小值的index
     */

    public int getMinFromShortestPath()
    {
        
        int minDist = INFINITY; // assume minimum

        int indexMin = 0;
        for ( int j = 1; j < nVerts; j++ ) // for each vertex,

        { // if it's in tree and

            if ( !vertexList[j].isInTree && // smaller than old one

                    shortestPath[j].distance < minDist )
            {
                minDist = shortestPath[j].distance;
                indexMin = j; // update minimum

            }
        } // end for

        return indexMin;
    }
    
    /**
     * 添加一条边
     * @param start 边的起点
     * @param end 边的终点
     * @param weight 边的权重
     */

    public void addEdge( int start, int end, int weight )
    {
        adjMat[start][end] = weight;    //有方向

    }
    
    /**
     * 添加一个节点
     *
     * @param lab
     */

    public void addVertex( char lab ) // argument is label

    {
        vertexList[nVerts++ ] = new Vertex( lab );
    }
}

其他类:

package zieckey.datastructure.study.graph;

/**
 * 在最短路径问题中,保存距离和到达该节点前最后一个必经节点
 *
 * @author zieckey
 */

public class DistanceParent
{
    public int    distance;    // distance from start to this vertex

    public int    parentVert; // current parent of this vertex

    public DistanceParent( int pv, int d ) // constructor

    {
        distance = d;
        parentVert = pv;
    }
}

===

package zieckey.datastructure.study.graph;

/**
 *
 * 图中的(节)点。
 *
 * @author zieckey
 *
 */

class Vertex
{
    public char        label;        // label (e.g. 'A')

    public boolean    wasVisited;
    public boolean    isInTree;

    public Vertex( char lab ) // constructor

    {
        label = lab;
        wasVisited = false;
        isInTree = false;
    }

} // end class Vertex

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/cuiyafang212/article/details/2740181
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞