最小生成树之prim算法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树之prim算法相关的知识,希望对你有一定的参考价值。
图片描述
算法思想
在算法中的每一步,把一个节点当作根并往上加边,这样就可以把相关联的顶点加到增长中的树中
选择边(u,v),使得(u,v)的值是所有u在树上但是v不在树上的边中值最小的,从而找出新顶点v加入到这棵树中
算法思路
Prim算法基本和Dijkstra算法一样
顶点结构包括
dist ——> 连接v到已知顶点的最短边的权
path——> 导致顶点v的dist改变的最后的顶点
kown——>标记该顶点是否为处理过
1.选取一个顶点作为树根
2.从到该树根最近的顶点v为中心(标记处理),探索能到达v的顶点w的dist是否需要被更新
此处
dist = min(dist,Cv,w)
3.顶点v作为树根
4.重复2-3步骤
代码实现
邻接链表实现
#include <iostream> #include <cstdlib> #define VERSIZE 7 #define NotVertex -1 #define Infinity 100000 using namespace std; typedef int Vertex; typedef struct vernode VerNode;//定义顶点结构 typedef struct tablelist Table;//定义邻接表 struct vernode { Vertex ver; int weight;//权重 VerNode * pNext; }; struct tablelist { VerNode header;//表头 bool known; int dist;//连接v到已知顶点的最短边的权 Vertex path;//导致dist最后改变的顶点 }T[VERSIZE]; //初始化标表+读图 void InitTable(Table T[], int n, int m)//顶点数n 边数m { int i = 0; for (i = 1; i <= n; i++)//初始化表头 { T[i].header.ver = i; T[i].header.weight = 0;//到自身的权重为0 T[i].header.pNext = NULL; T[i].dist = Infinity; T[i].known = false; T[i].path = NotVertex; } Vertex u, v;//边(u,v) int wei = 0; VerNode * ptemp; for (i = 1; i <= m; i++) { cout << "请输入第" << i << "条边:"; cin >> u >> v; cout << "请输入边(" << u << "," << v << ")的权重:"; cin >> wei; ptemp = (VerNode*)malloc(sizeof(VerNode));//将权重记到两个表中 ptemp->ver = v; ptemp->weight = wei; ptemp->pNext = T[u].header.pNext; T[u].header.pNext = ptemp; ptemp = (VerNode*)malloc(sizeof(VerNode)); ptemp->ver = u; ptemp->weight = wei; ptemp->pNext = T[v].header.pNext; T[v].header.pNext = ptemp; } } //找出到上一个点距离最小的顶点 Vertex FindMinIndex(Table T[], int n) { int i = 0; int min = Infinity; Vertex min_index = NotVertex; for (i = 1; i <= n; i++) { if (!T[i].known && T[i].dist < min) { min = T[i].dist; min_index = i; } } return min_index; } int prim(Table T[], Vertex source,int n) { int sum = 0; int i = 0; T[source].dist = 0;//源点到源点的距离为0 T[source].known = true;//源点已知 sum = T[source].dist; //在做循环处理前 初始化 VerNode * ptemp; ptemp = T[source].header.pNext; Vertex w; while (ptemp) { w = ptemp->ver; T[w].dist = ptemp->weight; T[w].path = source; ptemp = ptemp->pNext; } Vertex v; //处理n-1个顶点 for (i = 1; i <= n - 1; i++) { //找出到上一个点距离最小的顶点 v = FindMinIndex(T, n); if (v == NotVertex) break; T[v].known = true; sum += T[v].dist; ptemp = T[v].header.pNext;//找出顶点V所能到的顶点看是否能跟新他们的dist while (ptemp) { w = ptemp->ver; if (!T[w].known && T[w].dist > ptemp->weight)//进行跟新操作 { T[w].dist = ptemp->weight; T[w].path = v; } ptemp = ptemp->pNext; } } return sum; } int main() { Table T[VERSIZE]; InitTable(T, 7, 12); cout << prim(T, 1, 7)<< endl; system("pause"); return 0; }
邻接矩阵实现
#include <iostream> #include <cstdlib> #define Infinity 10000 #define VERSIZE 8 #define notvertex -1 using namespace std; typedef int Vertex; int dist[VERSIZE];//连接v到已知顶点的最短边权 bool S[VERSIZE];//将处理过的顶点设置为true Vertex path[VERSIZE];//存储到该顶点的上一个顶点 void ReadGraph(int Graph[VERSIZE][VERSIZE], int m)// 边m { int i = 0; Vertex u, v; int weight; for (i = 1; i <= m; i++) { cout << "请输入第" << i << "条边:"; cin >> u >> v; cout << "请输入边(" << u << "," << v << ")的权重:"; cin >> weight; Graph[u][v] = weight; Graph[v][u] = weight; } } //在没处理过的顶点里 找出距离源点最近的顶点 Vertex FindMinIndex() { int min = Infinity; Vertex min_index = 0; for (int i = 1; i< VERSIZE; i++) { if (!S[i] && dist[i]<min) { min = dist[i]; min_index = i; } } return min_index; } //算法关键 int prim(int Graph[VERSIZE][VERSIZE], Vertex source) { int sum = 0; int i = 0; // 初始化数组 从顶点为1开始能直接到达source的 初始化dis数组 0代表不可达 for (i = 1; i < VERSIZE; i++) { dist[i] = (Graph[source][i] == 0 ? Infinity : Graph[source][i]); S[i] = false; if (dist[i] != Infinity) path[i] = source; else path[i] = notvertex; } //源点到自身 dist[source] = 0; S[source] = true; sum = dist[source]; //循环VERSIZE-1次 for (int count = 1; count < VERSIZE; count++) { Vertex u = FindMinIndex();//找出距离源点最近的顶点 S[u] = true;//标记为已知 sum += dist[u]; for (int v = 1; v < VERSIZE; v++) { if (Graph[u][v] != 0 && !S[i])//u可达v 且 v未知 { if (dist[v] >Graph[u][v]) { dist[v] = Graph[u][v]; path[v] = u; } } } } return sum; } int main() { int i = 0, j = 0; int Graph[VERSIZE][VERSIZE] = { 0 }; for (i = 1; i < VERSIZE; i++)//初始化二维数组 { for (j = 1; j < VERSIZE; j++) Graph[i][j] = 0; } ReadGraph(Graph,12); cout << prim(Graph, 1) << endl; system("pause"); return 0; }
实验结果
THOUGHTS
Prim算法和Dijkstra算法十分相似,于是用了我上篇的博客,改了dist的判断
嗯,每天努力一点就好。
博客参考自《数据结构与算法分析》
以上是关于最小生成树之prim算法的主要内容,如果未能解决你的问题,请参考以下文章