/* 图结构,邻接矩阵形式 */ ElemType nodes[n]; int edges[n][n]; prim_or_dijkstra( int index, bool usePrim ) /* 起点 */ { int dist[n] = { INF }; /* 从起点开始,到其他所有边的距离 */ int distIndex[n] = { -1 }; int visited[n] = { 0 }; int selected = index; /*选中的点 */ /* 初始化起点的可达边距离 */ for ( i = 0; i < nodes.length; i++ ) /* edges[起点][终点]=权重(不是INF就有边),穷举 */ { if ( visited[i] ) break; visited[i] = true; if ( edges[selected][i] != INF ) { dist[i] = edges[selected][i]; /* index到可达边的距离 */ } } for ( k = 0; k < nodes.length - 1; k++ ) /* n-1次循环取点 */ { visited[selected] = true; int min = INF; int sel = -1; for ( i = 0; i < nodes.length; i++ ) /* edges[起点][终点]=权重(不是INF就有边),穷举 */ { if ( visited[i] ) break; /* 属于同一集合,不必考虑 */ if ( edges[selected][i] != INF ) { if ( min > dist[i] ) { min = dist[i]; sel = i; } /* min=已经被选中的点的集合到其他单独的点的最短距离 */ /* sel=相应的点 */ } } distIndex[sel] = selected; /* sel->selected映射,存放边 */ /* 一个sel只对应一个selected, */ /* 一个selected对应多个sel */ /* 第一次distIndex v2->v1 */ selected = sel; /*选中的点要更新 */ /* 此时 */ /* prim中令 dist[selected]=0 */ /* dijkstra不添加代码 */ if ( usePrim ) { dist[selected] = 0; } for ( i = 0; i < nodes.length; i++ ) /* selected->i,更新其他边 */ /* 由于selected已经是集合的一部分, */ /* selected的可达边的距离属于集合的可达边的距离 */ { /* 在所有的集合的可达边(不包含集合自身)的距离中取较小值 */ /*下面是两种方法相同的部分 */ if ( !visited[i] && dist[i] > dist[selected] + edges[selected][i] ) { dist[i] = dist[selected] + edges[selected][i] } } }
联系:
两者在连边时,用的是同一种贪心策略,即对于将扩展的集合总是在非扩展的点中找一条最短的边入集合,并用新入集合的点修改剩下点的到集合的最短路。
共同点:都有visited标记数组,dist数组,min,distIndex数组
注意:网上大多数教程中,prim算法是没有visited数组的,它用令dist[]=0来简化,而在这里,两种方法都用了visited数组,减少了差异性
区别:
在于dist的修改和意义
dijkstra仅仅就多了一个dist[selected],用做累积距离
而prim中由于dist[selected]=0,故可消去dist[selected]
prim
if(!visited[i] && dist[i] > edges[selected][i])
{dist[i] = edges[selected][i];}
//解释:prim中集合内部的边看做短路,可忽略,长度为0
dijkstra
if(!visited[i]
&& dist[i] > dist[selected]+ edges[selected][i])
{dist[i] = dist[selected]+ edges[selected][i]}
//解释:dijkstra中集合内部的边不可忽略,长度存在