1.prim算法概述
普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。
2.prim算法详解
图例 | 说明 | 不可选 | 可选 | 已选(Vnew) |
此为原始的加权连通图。每条边一侧的数字代表其权值。 | - | - | - | |
顶点D被任意选为起始点。顶点A、B、E和F通过单条边与D相连。A是距离D最近的顶点,因此将A及对应边AD以高亮表示。 | C, G | A, B, E, F | D | |
下一个顶点为距离D或A最近的顶点。B距D为9,距A为7,E为15,F为6。因此,F距D或A最近,因此将顶点F与相应边DF以高亮表示。 | C, G | B, E, F | A, D | |
算法继续重复上面的步骤。距离A为7的顶点B被高亮表示。 | C | B, E, G | A, D, F | |
在当前情况下,可以在C、E与G间进行选择。C距B为8,E距B为7,G距F为11。点E最近,因此将顶点E与相应边BE高亮表示。 | 无 | C, E, G | A, D, F, B | |
这里,可供选择的顶点只有C和G。C距E为5,G距E为9,故选取C,并与边EC一同高亮表示。 | 无 | C, G | A, D, F, B, E | |
顶点G是唯一剩下的顶点,它距F为11,距E为9,E最近,故高亮表示G及相应边EG。 | 无 | G | A, D, F, B, E, C | |
所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为39。 | 无 | 无 | A, D, F, B, E, C, G |
3.java代码实现
/**
* @author wangli
* @data 2022/6/13 14:44
* @Description:
*/
public class PrimArithmetic {
@Test
public void PrimArithmeticDemo(){
char[] vertexs = new char[] {'A','B','C','D','E','F','G'};
Graph graph = new Graph(vertexs);
int[][] edges = new int[][] {
{10000,5,7,10000,10000,10000,2},
{5,10000,10000,9,10000,10000,3},
{7,10000,10000,10000,8,10000,10000},
{10000,9,10000,10000,10000,4,10000},
{10000,10000,8,10000,10000,5,4},
{10000,10000,10000,4,5,10000,6},
{2,3,10000,10000,4,6,10000}};
createTree(graph,vertexs,edges);
graph.showGraph();
minPrim(graph,0);
}
/**
* 最小生成树
* @param graph
* @param v 起始节点
*/
public void minPrim(Graph graph,int v){
//visited[] 标记结点是否被访问过
Integer[] visiteds = new Integer[graph.vertex.length];
for (int i = 0; i < visiteds.length; i++) {
visiteds[i]=0;
}
visiteds[v]=1;
int min=10000;
// 记录起始点
int startVertex=-1;
// 记录终点
int endVertex=-1;
for (int i = 0; i < graph.vertex.length; i++) {
for (int j = 0; j < graph.vertex.length; j++) {
for (int k = 0; k < graph.vertex.length; k++) {
if (visiteds[j]==1&&visiteds[k]==0&&graph.edges[j][k]<min){
min=graph.edges[j][k];
startVertex=j;
endVertex=k;
}
}
}
System.out.println("边<" + graph.vertex[startVertex] + graph.vertex[endVertex] + ">权值:" + min);
// 表示该点以及被遍历过
visiteds[endVertex]=1;
min=10000;
}
}
/**
* 创建树
*/
public void createTree(Graph graph,char[] vertexes,int[][] edges){
for (int i = 0; i < vertexes.length; i++) {
graph.vertex[i]=vertexes[i];
for (int j = 0; j < vertexes.length; j++) {
graph.edges[i][j]=edges[i][j];
}
}
}
@Data
static class Graph{
// 节点
private char[] vertex;
// 邻接矩阵
private int[][] edges;
public Graph(char[] vertex) {
this.vertex=vertex;
edges=new int[vertex.length][vertex.length];
}
/**
* 查看邻接矩阵
*/
public void showGraph(){
for (int i = 0; i < vertex.length; i++) {
for (int j = 0; j < vertex.length; j++) {
System.out.printf("%15d",edges[i][j]);
}
System.out.println();
}
}
}
}
生成的最短路径如下