prim算法和Dijkstra算法都是图论或者离散数学里面的典型算法,由于两者在实现策略上有很多相似之处,现做以比较:
同:
(1)、两者都属于贪心算法的应用;
(2)、都使用了堆结构;
(3)、都有松弛操作;
异:
(1)、给一堆村子之间修路,保证花费最小,用prim算法;
从一个村子到其他所有村子修路,并且希望花费最小,用Dijkstra。
(2)、prim适用于无相连通图;Dijkstra则适用于有向图;
(3)、松弛条件不一样:prim是从S到V-S进行松弛(V是所有节点集合,S是加入最小生成树的集合);而Dijkstra的松弛操作是从单源点到其他所有节点的松弛。
Prim算法:
数据结构:
int[] adjvex = new int[MAXVEX];//每一个节点的邻接节点
int[] lowcost = new int[MAXVEX];//当前S到V-S的最短开销
松弛操作:
if(lowcost[j] != 0 && G.arc[k][j] < lowcost[j]){
lowcost[j] = G.arc[k][j];
adjvex[j] = k;
}
代码:
package graph;
public class prim {
static final int INF = 9999;
static final int MAXVEX = 9;
class MGraph{
int numVertexes = 9;
private int[][] arc = {
{0,10,INF,INF,INF,11,INF,INF,INF},
{10,0,18,INF,INF,INF,16,INF,12},
{INF,INF,0,22,INF,INF,INF,INF,8},
{INF,INF,22,0,20,INF,INF,16,21},
{INF,INF,INF,20,0,26,INF,7,INF},
{11,INF,INF,INF,26,0,17,INF,INF},
{INF,16,INF,INF,INF,17,0,19,INF},
{INF,INF,INF,16,7,INF,19,0,INF},
{INF,12,8,21,INF,INF,INF,INF,0}
};
}
public static void main(String[] args){
MGraph G = new prim().new MGraph();//内部类的调用不同于其他类
MiniSpanTree_prim(G);
}
static void MiniSpanTree_prim(MGraph G){
int min,i,j,k;
int[] adjvex = new int[MAXVEX];//每一个节点的邻接节点
int[] lowcost = new int[MAXVEX];//当前S到V-S的最短开销
lowcost[0] = 0;//v0加入生成树
adjvex[0] = 0;//S集合中0与0不临接
for(i = 1;i < G.numVertexes;i++){//初始化设置边界
lowcost[i] = G.arc[0][i];
adjvex[i] = 0;//初始状态S中只有v0,其它均不邻接
}
for(i = 1;i < G.numVertexes;i++){
min = INF;
j = 1; k = 0;
while(j < G.numVertexes)//循环全部节点,每次只选最小的
{
if(lowcost[j] != 0 && lowcost[j] < min)//不到没加入S而且还可以经过更短的路到达
{
min = lowcost[j];
k = j;
}
j++;
}
System.out.print("("+adjvex[k]+","+k+")");
lowcost[k] = 0;//把这个到S最小的点加入S
for(j = 1;j < G.numVertexes;j++){//既然下标为k的节点加入了,那么就要更新lowcost数组
if(lowcost[j] != 0 && G.arc[k][j] < lowcost[j]){
lowcost[j] = G.arc[k][j];
adjvex[j] = k;
}
}
}
for(i = 0;i < G.numVertexes;i++)
{
System.out.print(lowcost[i]+" ");
}
System.out.print("\n");
for(i = 0;i < G.numVertexes;i++)
{
System.out.print(adjvex[i]+" ");
}
}
}
DijkStra算法:
数据结构:
boolean[] visit = new boolean[MAXVEX];//用来记录是否到达过某节点
int[] dist = new int[MAXVEX];//用来记录单原点到其它节点路径
松弛操作:
if(!visit[j] && dist[j] > dist[k] + G.arc[k][j])//松弛
{
dist[j] = dist[k] + G.arc[k][j];
}
代码:
package graph;
public class Dijkstra {
static final int INF = 999999;
static final int MAXVEX = 9;
class MGraph{
int numVertex = 9;
int[][] arc = {
{0,1,5,INF,INF,INF,INF,INF,INF},
{1,0,3,7,5,INF,INF,INF,INF},
{5,3,0,INF,1,7,INF,INF,INF},
{INF,7,INF,0,2,INF,3,INF,INF},
{INF,5,1,2,0,3,6,9,INF},
{INF,INF,7,INF,3,0,INF,5,INF},
{INF,INF,INF,3,6,INF,0,2,7},
{INF,INF,INF,INF,9,5,2,0,4},
{INF,INF,INF,INF,INF,INF,7,4,0}
};
}
public static void main(String[] args){
shortestPath(new Dijkstra().new MGraph());
}
public static void shortestPath(MGraph G){
boolean[] visit = new boolean[MAXVEX];//用来记录是否到达过某节点
int[] dist = new int[MAXVEX];//用来记录单原点到其它节点路径
int min;
int j,i,k = 0;
for(i = 1;i < G.numVertex;i++){
visit[i] = false;
dist[i] = G.arc[0][i];//前驱结点只有v0
}
visit[0] = true;
dist[0] = 0;
for(i = 1;i < G.numVertex;i++){
min = INF;
for(j = 0;j < G.numVertex;j++)
{
if(!visit[j] && dist[j] < min)
{
k = j;
min = dist[j];
}
}
visit[k] = true;//将节点Vk加入S
System.out.print(k+" ");
for(j = 0;j < G.numVertex;j++){//更新V0到其它节点的最短路径
if(!visit[j] && dist[j] > dist[k] + G.arc[k][j])//松弛
{
dist[j] = dist[k] + G.arc[k][j];
}
}
}
System.out.print("\n");
for(i = 0;i < G.numVertex;i++){
System.out.print(dist[i]+" ");
}
}
}